MyBatis
打算使用一个小工具用来批量生成产品信息;开始尝试使用MySql的循环语句,但是尝试了几次之后发现语法问题没有成功,而且sql的维护性,扩展性比较差;于是打算采用mybatis,之前使用过mybatis2,现在调查一下mybatis3,不禁有一种惊艳的感觉,我指的是Mybatis3增加了扫描功能;另外提供了一个注解功能(用以将xml的配置放置到类中)以及SQL对象(可以通过where,join等函数拼接出一个sql,形式上和linq有点类似),有些鸡肋;但是这恰说明MyBatis在走向完善,满足越来越小的细分市场。
闲言少叙上一个Demo,使用Mybatis的基本核心功能构建一个增加功能。
基本类
public class Product {
private String id;
private String name;
private String categoryId;
private String picUrl;
private String createDate;
private String createUserId;
private String updateDate;
private String updateUserId;
private String price;
private String introduction;
private String keywords;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCategoryId() {
return categoryId;
}
public void setCategoryId(String categoryId) {
this.categoryId = categoryId;
}
public String getPicUrl() {
return picUrl;
}
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
}
public String getCreateDate() {
return createDate;
}
public void setCreateDate(String createDate) {
this.createDate = createDate;
}
public String getCreateUserId() {
return createUserId;
}
public void setCreateUserId(String createUserId) {
this.createUserId = createUserId;
}
public String getUpdateDate() {
return updateDate;
}
public void setUpdateDate(String updateDate) {
this.updateDate = updateDate;
}
public String getUpdateUserId() {
return updateUserId;
}
public void setUpdateUserId(String updateUserId) {
this.updateUserId = updateUserId;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getIntroduction() {
return introduction;
}
public void setIntroduction(String introduction) {
this.introduction = introduction;
}
public String getKeywords() {
return keywords;
}
public void setKeywords(String keywords) {
this.keywords = keywords;
}
}
main执行函数:
import java.util.List;
import org.apache.ibatis.session.SqlSession;
public class Main {
public static void main(String[] args) {
insertUser();
}
/**
* 新增用户
*/
private static void insertUser() {
SqlSession session = DBTools.getSession();
ProductMapper mapper = session.getMapper(ProductMapper.class);
Product p = new Product();
p.setCategoryId("1");
p.setName("Mobile");
p.setIntroduction("Vivo, whose mobile is singing");
p.setPicUrl("");
try {
mapper.insertProduct(p);
session.commit();
System.out.println("插入完毕");
Product product = mapper.selectProduct(1);
System.out.println("productName is:" + product.getName());
List<Product> products = mapper.selectAllProduct();
for(Product pro: products){
System.out.println("get all product, p name is: " + pro.getName());
}
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}
}
}
这里用到了DBTools来获得Mybatis的sqlSession,下面是DBTools的定义:
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class DBTools {
public static SqlSessionFactory sessionFactory;
static{
try {
//使用MyBatis提供的Resources类加载mybatis的配置文件
Reader reader = Resources.getResourceAsReader("mybatis.xml");
//构建sqlSession的工厂
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (Exception e) {
e.printStackTrace();
}
}
//创建能执行映射文件中sql的sqlSession
public static SqlSession getSession(){
return sessionFactory.openSession();
}
}
至此,发现了sessionFactory是通过读取资源文件来 mybatis.xml来获取数据源信息:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 引入外部配置文件 --> <properties resource="config.properties"></properties> <typeAliases> <package name="lorrywork.emall.insertData" /> </typeAliases> <!-- 配置mybatis运行环境 --> <environments default="cybatis"> <environment id="cybatis"> <!-- type="JDBC" 代表使用JDBC的提交和回滚来管理事务 --> <transactionManager type="JDBC" /> <!-- mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI --> <!-- POOLED 表示支持JDBC数据源连接池 --> <!-- UNPOOLED 表示不支持数据源连接池 --> <!-- JNDI 表示支持外部数据源连接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <mappers> <!-- 告知映射文件方式1,一个一个的配置 <mapper resource="com/cy/mybatis/mapper/UserMapper.xml"/> --> <!-- 告知映射文件方式2,自动扫描包内的Mapper接口与配置文件 --> <package name="lorrywork.emall.insertData" /> </mappers> </configuration>
properties:定义了数据库相关的propeties文件路径,这样可以保证整个系统只需要在一个地方配置数据库信息就可以被应用以及MyBatis使用;
typeAlias:类型别名,用于为比较长的类命名空间指定一个简称(别名),这样就可以在在下面指定的mapper xml中使用该简称来指定返回值以及参数类型;
environments:环境信息,可以在这个节点下面定义多个数据库库信息(environment),比如测试数据库信息,部署数据库信息等 。
mappers:Mapper类,类似于spring的自动扫描机制,只需要指定包名,这个也是我觉得mybatis3的惊艳之处,便可以首先mybatis自动扫描加载该包下面所有的mapper文件(xml文件)。当然也可以采用传统的指定具体xml的方式。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="lorrywork.emall.insertData.ProductMapper">
<insert id="insertProduct" useGeneratedKeys="true">
insert into product
(name,categoryId,picUrl,createUserId,createDate,updateUserId,updateDate,price,introduction,keywords)
values (#{name},#{categoryId},#{picUrl},#{createUserId},NOW(),#{updateUserId},NOW(),#{price},#{introduction},#{keywords})
</insert>
<select id="selectProduct" parameterType="int" resultType="Product">
select * from product where id=#{id}
</select>
<select id="selectAllProduct" resultType="Product">
select * from product
</select>
</mapper>
<insert id="insertProduct" useGeneratedKeys="true">
insert into product
(name,categoryId,picUrl,createUserId,createDate,updateUserId,updateDate,price,introduction,keywords)
values (#{name},#{categoryId},#{picUrl},#{createUserId},NOW(),#{updateUserId},NOW(),#{price},#{introduction},#{keywords})
</insert>
<select id="selectProduct" parameterType="int" resultType="Product">
select * from product where id=#{id}
</select>
<select id="selectAllProduct" resultType="Product">
select * from product
</select>
</mapper>
对于insert不需要指定参数类型,将会自动根据参数来匹配#{name}, #{category},采用的是反射机制,这一点我觉得可能会对于性能有影响,这个还是需要验证。
select就不多说了,注意这里的returnType的“product”,是对应于mybatis.xml中定义的typeAlias。
最后mapper.xml的namespace中指定了绑定的mapper的接口:
import java.util.List;
public interface ProductMapper {
public void insertProduct(Product p) throws Exception;
public Product selectProduct(int productId) throws Exception;
public List<Product> selectAllProduct() throws Exception;
}
最开始介绍的mybatis中提供了注解,就是在这个接口中使用。
在了解mybatis3的过程,发现mybatis的中文官网不错,可以参考一下。