MyBatis是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis可以使用简单的XML配置或注解来配置和映射原生信息,将接口和Java的POJO(Plain Ordinary Java Object,普通Java对象)映射成数据库中的数据。
asm-3.3.1.jar
cglib-2.2.2.jar
commons-logging-1.1.1.jar
javassist-3.17.1-GA.jar
log4j-1.2.17.jar
mybatis-3.2.1.jar
mysql-connector-java-5.1.26-bin.jar
slf4j-api-1.7.2.jar
slf4j-log4j12-1.7.2.jar
public class Product {
private Long id;
private Long dir_id; // 商品分类编号
private String productName;// 商品名称
private String supplier; // 供应商
private String brand; // 品牌
private Double salePrice; // 零售价
private Double cutoff; // 折扣比例
private Double costPrice; // 进价
。。。。// Getter与Setter略过
}
MyBatis的核心配置文件放在项目的资源文件resources目录下,文件命名为mybatis-config.xml,具体的配置如下:
mybatis-config.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>
<!-- 引入jdbc.properties配置文件 -->
<properties resource="jdbc.properties"></properties>
<!--别名的配置,类的全限定名可以使用别名
alias:别名名称
type:别名所对应的类的全限定名,别名的使用与大小写无关-->
<typeAliases>
<typeAlias alias="Product" type="cn.yif.mybatis.domain.Product"></typeAlias>
<typeAlias alias="User" type="cn.yif.mybatis.domain.User"></typeAlias>
</typeAliases>
<!--MyBatis环境配置-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 数据库连接配置 -->
<dataSource type="POOLED">
<property name="driver" value="${driverClassName}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!—- Mapper.xml文件配置 -->
<mappers>
<mapper resource="cn/yif/mybatis/mapper/ProductMapper.xml"/>
<mapper resource="cn/yif/mybatis/mapper/UserMapper.xml"/>
</mappers>
</configuration>
driverClassName = com.mysql.jdbc.Driver url = jdbc:mysql://localhost:3306/mybatis01_0317 username = root password = admin
映射文件XXXMapper.xml是对应Domain属性与DaoImpl中方法并与数据库字段产生关系的唯一映射配置,在这里面我们可以存放基础的CRUD对应的Sql文件,去执行数据库的操作:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:用来找唯一的mapper文件,一般是domain的全路径名+Mapper来命名 -->
<mapper namespace="cn.yif.mybatis.domain.Product">
<!--id表示唯一标识,parameterType标识参数的类型,resultType表示返回值的类型-->
<select id="queryById" parameterType="Long" resultType="cn.yif.mybatis.domain.Product">
select * from Product where id = #{id}
</select>
<select id="queryAll" resultType="cn.yif.mybatis.domain.Product">
select * from Product
</select>
<!--添加时拿到返回的主键:
parameterType:需要传入的对象
useGeneratedKeys:是否需要主键
keyColumn:数据库中对应主键的列
keyProperty:对象中主键对应的id-->
<insert id="insert" parameterType="cn.yif.mybatis.domain.Product" useGeneratedKeys="true"
keyColumn="id" keyProperty="id">
insert into Product(productName, dir_id, salePrice, supplier, brand, cutoff, costPrice)
values (#{productName}, #{dir_id}, #{salePrice}, #{supplier}, #{brand}, #{cutoff}, #{costPrice})
</insert>
<update id="update" parameterType="cn.yif.mybatis.domain.Product">
update product set productName = #{productName}, dir_id = #{dir_id}, salePrice = #{salePrice},
supplier = #{supplier}, brand = #{brand}, cutoff = #{cutoff}, costPrice = #{costPrice}
where id = #{id}
</update>
<delete id="delete" parameterType="Long">
delete from product where id = #{id}
</delete>
</mapper>
首先我们需要读取mybatis-config.xml核心资源文件,通过SqlSessionFactoryBuilder构建者来创建一个SqlSessionFactory工厂,通过SqlSessionFactory来创建SqlSession对象。通过SqlSession就可以执行我们的数据库增删查改的xml中的配置语句,最终使用之后还需要及时关闭SqlSession语句对象。基于这种增删改查操作都是同样的我们可以抽取一个工具类MyBatisUtil,具体实现如下:
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory = null;
private static Reader reader = null;
// 因为sqlSessionFactory是线程安全的,每次初始化只需要创建一个SqlSessionFactory实例
static {
try {
reader = Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
// SqlSession是线程不安全的类,每个线程内单独去获取当前线程的SqlSession
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
// 关闭SqlSession
public static void closeSqlSession(SqlSession sqlSession){
if(sqlSession != null){
sqlSession.close();
}
}
}
ProductDaoImpl.java
public class ProductDaoImpl implements IProductDao {
public static final String NAME_SPACE = "cn.yif.mybatis.domain.Product.";
@Override
public void insert(Product product) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
sqlSession.insert(NAME_SPACE + "insert", product);
MyBatisUtil.closeSqlSession(sqlSession);
}
@Override
public void update(Product product) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
sqlSession.update(NAME_SPACE + "update", product);
MyBatisUtil.closeSqlSession(sqlSession);
}
@Override
public void delete(Long id) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
sqlSession.delete(NAME_SPACE + "delete", id);
MyBatisUtil.closeSqlSession(sqlSession);
}
@Override
public Product queryById(Long id) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
Product product = sqlSession.selectOne(NAME_SPACE + "queryById", id);
MyBatisUtil.closeSqlSession(sqlSession);
return product;
}
@Override
public List<Product> queryAll() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
List<Product> list = sqlSession.selectList(NAME_SPACE + "queryAll");
MyBatisUtil.closeSqlSession(sqlSession);
return list;
}
}
public class ProductDaoImplTest {
@org.junit.Test
public void insert() {
IProductDao productDao = new ProductDaoImpl();
Product product = new Product();
product.setProductName("测试产品112");
product.setBrand("TestBrand");
product.setCostPrice(237.5);
product.setCutoff(0.85);
product.setDir_id(4L);
product.setSalePrice(520.0);
product.setSupplier("甲骨文");
System.out.println("添加之前,查看id:" + product.getId());
productDao.insert(product);
System.out.println("添加之后,查看id:" + product.getId());
}
@org.junit.Test
public void update() {
IProductDao productDao = new ProductDaoImpl();
Product product = new Product();
product.setId(22L);
product.setProductName("测试产品114");
product.setBrand("TestBrand114");
product.setCostPrice(237.1);
product.setCutoff(0.45);
product.setDir_id(4L);
product.setSalePrice(520.1);
product.setSupplier("甲骨文114");
productDao.update(product);
}
@org.junit.Test
public void delete() {
IProductDao productDao = new ProductDaoImpl();
productDao.delete(24L);
}
@org.junit.Test
public void queryById() {
IProductDao productDao = new ProductDaoImpl();
Product product = productDao.queryById(31L);
System.out.println(product);
}
@org.junit.Test
public void queryAll() {
IProductDao productDao = new ProductDaoImpl();
List<Product> list = productDao.queryAll();
for (Product product: list) {
System.out.println(product);
}
}
}
对应在XXXMapper.xml中需要做如下配置:
<!--添加时拿到返回的主键:
parameterType:需要传入的对象
useGeneratedKeys:是否需要主键
keyColumn:数据库中对应主键的列
keyProperty:对象中主键对应的id-->
<insert id="insert" parameterType="cn.yif.mybatis.domain.Product" useGeneratedKeys="true"
keyColumn="id" keyProperty="id">
insert into Product(productName, dir_id, salePrice, supplier, brand, cutoff, costPrice)
values (#{productName}, #{dir_id}, #{salePrice}, #{supplier}, #{brand}, #{cutoff}, #{costPrice})
</insert>
Log4j是MyBatis提供的日志打印依赖jar包,可以帮助我们进行分析和定位问题。在Log4j日志配置文件中我们可以规定日志打印显示的级别:
日志等级:从低到高(大小写没有关系,但是在配置的时候都建议使用大写)
等级从低到高(大小写没有关系,但是在配置的时候建议都写大写) TRACE:详细 (建议开发的时候用) DEDUG:调试,类似于System.out.print INFO:信息,类似于JPA打印sql等级 WARN:警告,程序可以正常运行,出现提示 ERROR:错误,出现异常 (建议正式环境)
具体配置文件应命名为log4j.properties,配置如下:
log4j.properties:
#log4j.properties(日志文件): #全局配置:先配置一个日志的根,这个级别是ERROR log4j.rootLogger=ERROR, stdout #局部配置 :把左边包名改成你自己的包名:表示我们自己这个路径下的代码级别 #级别说明:TRACE(详细)、Debug(调试)、Info(信息)、Warn(警告)、Error(错误) log4j.logger.cn.yif.mybatis=TRACE #在控制台输出和输出的格式 log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
① MyBatis的内置别名
MyBatis中包含内置别名,即无需配置,MyBatis框架自动涵盖的别名,可以直接使用。
具体包含如下别名类型:
② 自定义别名
具体配置及其使用:
别名需要在mybatis-config.xml中使用,位置在<properties>标签之后:
<!--别名的配置,类的全限定名可以使用别名
alias:别名名称
type:别名所对应的类的全限定名,别名的使用与大小写无关-->
<typeAliases>
<typeAlias alias="Product" type="cn.yif.mybatis.domain.Product"></typeAlias>
<typeAlias alias="User" type="cn.yif.mybatis.domain.User"></typeAlias>
</typeAliases>
使用别名:
在XXXMapper.xml文件中对应的类全限定名即可使用别名,且与大小写无关。
数据库中的列名与Domain类中的属性名不一致时,如果直接使用ResultType对应,执行Sql查询语句等会出现相应值为null的情况,这时需要配置ResultMap进行关系映射对应,告诉Sql这个数据库中的列是对应Domain类中的哪个属性,具体配置如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:用来找唯一的mapper文件,一般是domain的全路径名+Mapper来命名 -->
<mapper namespace="cn.yif.mybatis.domain.User">
<!--当Domain中的属性与数据库中的字段列不一致时,需要使用resultMap
id表示唯一标识,对应select中的resultMap
type表示返回值类型
column:对应数据库中的列名
property:对应Domain中类的属性字段-->
<resultMap id="userMap" type="User">
<result column="username" property="name"></result>
<result column="password" property="pwd"></result>
</resultMap>
<!--id表示唯一标识,parameterType标识参数的类型,resultType表示返回值的类型-->
<select id="getUserById" parameterType="Integer" resultMap="userMap">
select * from user where id = #{id}
</select>
</mapper>