文章目录
前言
mybatis是一个轻量级的ORM框架,之前我们已经学习了mybatis的基本概念,环境的搭建以及参数和结果处理,本章我们将继续学习mybatis剩余的内容,包括动态Sql,注解方式以及缓存。
一、懒加载
当我们在进行多表查询时,启动懒加载可以有效的缓解数据库的压力。首次查询我们只先查询主表中的信息,当用户需要用到关联表的信息时,才进行获取。Mybatis 一对一关联的 association 和一对多的 collection 可以实现懒加载。
注意:懒加载时要使用 resultMap,不能使用 resultType。
如何启动懒加载?
Mybatis 默认没有打开懒加载配置,需要在 SqlMapperConfig.xml 中通过 settings 配置 lazyLoadingEnabled 和lazyLoadTriggerMethods(一些方法会触发查询,导致懒加载无效,将value设置为空)来开启懒加载。
Employee里面的成员变量
public class Employee implements Serializable {
private Integer id;
private String name;
private String sex;
private Dept dept;
private Admin admin;
}
懒加载配置
<!--是否开启懒加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--指定哪些方法触发延迟查询 -->
<setting name="lazyLoadTriggerMethods" value=""/>
mapper映射文件代码
<select id="selectEmployeeLazy" resultMap="EmployeeResultLazyMap">
SELECT id,NAME,deptid,adminid FROM employee where id=#{id}
</select>
<resultMap id="EmployeeResultLazyMap" type="Employee">
<!--主键列-->
<id column="id" property="id"/>
<!--非主键列-->
<result property="name" column="name"/>
<association property="dept" javaType="Dept" fetchType="lazy" column="deptid" select="selectDeptLazy">
<result property="name" column="name"/>
</association>
<association property="admin" javaType="Admin" fetchType="lazy" column="adminid" select="selectAdminLazy">
<result property="name" column="name"/>
</association>
</resultMap>
<select id="selectEmployeeLazy" resultMap="EmployeeResultLazyMap">
SELECT id,NAME,deptid,adminid FROM employee where id=#{id}
</select>
<select id="selectDeptLazy" resultType="Dept">
SELECT NAME FROM dept WHERE id=#{deptid}
</select>
1.Select:指定关联查询懒加载对象的 Mapper Statement ID
2.column=“deptid”:关联查询时将 deptid 列的值传入 selectDeptLazy,并把查询结果映射到Employee的dept中去
测试代码
@org.junit.Test
public void select(){
SqlSession sqlSession= sessionFactory.openSession();
EmployeeMapper employeeMapper=sqlSession.getMapper(EmployeeMapper.class);
Employee employee=employeeMapper.selectEmployeeLazy(2);
System.out.println(employee.getName());
System.out.println(employee.getDept().getName());
System.out.println(employee.getAdmin().getName());
}
由运行结果可以得出,当我们在进行查询的时候并没有一次性把所有的信息都查出来,当我们需要用到dept和admin时,才会进行新的查询。
二、注解方式
mybatis提供了注解的实现方法,可以不把sql代码写在mapper的映射文件中,使用注解方式直接写在接口的方法上面
常见的注解标签
@Insert : 插入 sql , 和 xml insert sql 语法完全一样
@Select : 查询 sql, 和 xml select sql 语法完全一样
@Update : 更新 sql, 和 xml update sql 语法完全一样
@Delete : 删除 sql, 和 xml delete sql 语法完全一样
@Param : 入参
@Results : 设置结果集合
@Result : 结果
接口中的方法
@Select("SELECT id,NAME,sex FROM employee")
@Results(id = "empMap", value = {@Result(column = "id", property = "id", id = true),
@Result(column = "name", property = "name"),
@Result(column = "sex", property = "sex")})
List<Employee> getEmployeesListByAnnotate();
测试代码
public void select(){
SqlSession sqlSession= sessionFactory.openSession();
EmployeeMapper employeeMapper=sqlSession.getMapper(EmployeeMapper.class);
List<Employee>list=employeeMapper.getEmployeesListByAnnotate();
for(Employee temp:list){
System.out.println(temp);
}
}
运行结果
三、动态SQL
MyBatis 的一个强大的特性之一是它的动态 SQL 能力,有条件的拼接sql字符串常常使程序员感到痛苦,mybatis可以解决这个问题。
MyBatis中用于实现动态SQL的元素主要有
3.1 if元素
if 标签可以对传入的条件进行判断
3.2 where元素
对于查询条件个数不确定的情况
<select id="getEmployeesList" parameterType="Employee" resultMap="EmployeeResultMap">
SELECT
e.id,
e.name ename,
e.sex,
d.name dname,
a.name aname
FROM employee e LEFT JOIN dept d ON d.id=e.deptid
LEFT JOIN admin a ON a.id=e.adminid
<where>
<if test="name != null & name != ''">
e.name like concat('%',#{name},'%')
</if>
<if test="sex != null & sex != ''">
AND e.sex= #{sex}
</if>
</where>
</select>
1.where元素会进行判断,如果where包含的标签有返回值,就插入一个where。
2.如果返回值以and或者or开头,则它会剔除掉and或者or
该动态sql支持姓名的单条件模糊查询,支持性别的单条件查询,支持姓名和性别的多条件查询,利用动态sql可以极大的简化了我们的sql代码拼写。
3.3 trim元素
当 WHERE后紧随AND或OR的时候,就去除AND或者OR
prefix 前缀
prefixOverrides 覆盖首部指定内容
<select id="getEmployeesList2" parameterType="Employee" resultMap="EmployeeResultMap">
SELECT
e.id,
e.name ename,
e.sex,
d.name dname,
a.name aname
FROM employee e LEFT JOIN dept d ON d.id=e.deptid
LEFT JOIN admin a ON a.id=e.adminid
<trim prefix="where" prefixOverrides="and">
<if test="name != null & name != ''">
and e.name like concat('%',#{name},'%')
</if>
<if test="sex != null & sex != ''">
AND sex= #{sex}
</if>
</trim>
</select>
3.4 choose元素
choose类似于switch,只执行其中一个条件。
<select id="getEmployees" resultType="Employee" parameterType="Employee">
SELECT
e.id,
e.name ename,
e.sex,
d.name dname,
a.name aname
FROM employee e LEFT JOIN dept d ON d.id=e.deptid
LEFT JOIN admin a ON a.id=e.adminid
<where>
<choose>
<when test="name != null & name != ''">
e.name like concat('%',#{name},'%')
</when>
<otherwise>
e.name ='张三'
</otherwise>
</choose>
</where>
</select>
如果 name != null & name != ’ ’ 则进行姓名的模糊查询,否则查找张三的信息
3.5 set元素
一般将其用在修改的sql中 Set 元素可以把最后一个逗号去掉
<update id="updateEmployee" parameterType="Employee">
update employee
<set>
<if test="name!=null">
name=#{name},
</if>
<if test="sex!=null">
sex=#{sex},
</if>
<if test="admin.id !=null">
adminid=#{admin.id},
</if>
</set>
<where>
id=#{id}
</where>
</update>
3.6 foreach元素
主要用在构建 in 条件中,它可以在 SQL 语句中进行迭代一个集合。
1.item:表示集合中每一个元素进行迭代时的别名
2.index:指定一个名字,用于表示在迭代过程中,每次迭代到的位置
3.open:表示该语句以什么开始
4.separator: 表示在每次进行迭代之间以什么符号作为分隔符
5.close: 表示以什么结束
6.collection:该属性是必须指定的,但是在不同情况下,该属性的值不一样
如果传入的是单参数且参数类型是一个 List 的时候,collection 属 性值为 list
如果传入的是单参数且参数类型是一个 array 数组的时候, collection 的属性值为 array
<!--主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合-->
<select id="selectEmployeeDeptIn" resultType="Employee" parameterType="Employee">
SELECT id,NAME,deptid,adminid FROM employee where deptid in
<foreach collection="list" item="deptid" open="(" separator="," close=")">
#{deptid}
</foreach>
</select>
接口中的方法
List<Employee> selectEmployeeDeptIn(List<Integer> list);
测试代码
List<Integer>list=new ArrayList<Integer>();
list.add(2);
list.add(3);
employeeMapper.selectEmployeeDeptIn(list);
该语义即为查找部门号为2或者3的员工信息
四、特殊符号处理
mybatis 中的 xml 文件中,存在一些特殊的符号,比如:<、>、"、&、<> 等,正常书写 mybatis 会报错,需要对这些符号进行转义。
五、缓存
为什么使用缓存:减轻数据库的压力,从数据库中查询出来的对象先不销毁,存在内存中,当以后再使用时直接从内存中读取,缓存主要用于select语句,减小对数据库的查询次数,提高数据库的内存。
5.1一级缓存
一级缓存的作用域是sqlsession,当同一个sqlsession执行了两次相同的sql语句,第一次读取到的数据会存储在内存中
第二次查询将不再从数据库中读取,直接从缓存中读取,当sqlsession结束后,一级缓存也就不存在。mybatis默认开启一级缓存
测试代码
@org.junit.Test
public void select() {
SqlSession sqlSession = sessionFactory.openSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Integer> list = new ArrayList<Integer>();
list.add(2);
employeeMapper.selectEmployeeDeptIn(list);
employeeMapper.selectEmployeeDeptIn(list);
}
从控制台信息可以看到只执行了一次查询
5.2一级缓存的生命周期
MyBatis 在开启一个数据库会话时:
1.创建一个新的SqlSession 对象
2.SqlSession对象中会有一个新的 Executor 对象
3.Executor 对象中持有一个新的PerpetualCache对象
4.如果SqlSession调用了close()方法,会释放掉一级缓存 PerpetualCache对象,一级缓存将不可用
注意:
SqlSession调用clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用
@org.junit.Test
public void select() {
SqlSession sqlSession = sessionFactory.openSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Integer> list = new ArrayList<Integer>();
list.add(2);
employeeMapper.selectEmployeeDeptIn(list);
/*清空缓存区域*/
sqlSession.clearCache();
employeeMapper.selectEmployeeDeptIn(list);
}
从控制台信息可以看到执行了二次查询
注意:
SqlSession 中执行了任何一个update操作(update()、delete()、 insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用
5.3二级缓存
二级缓存是 SqlSessionFactory 级别的,根据 mapper 的 namespace 划分区域 的,相同 namespace 的 mapper 查询的数据缓存在同一个区域
配置二级缓存
1.在mybatis中配置
<setting name="cacheEnabled" value="true"/>
2.在pojo类中实现序列化接口:Java.io. Serializable
3.在 Mapper 映射文件中添加,表示此 mapper 开启二级缓存
测试代码
@org.junit.Test
public void select1() {
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
EmployeeMapper employeeMapper = sqlSession1.getMapper(EmployeeMapper.class);
EmployeeMapper employeeMapper2 = sqlSession2.getMapper(EmployeeMapper.class);
List<Integer> list = new ArrayList<Integer>();
list.add(2);
employeeMapper.selectEmployeeDeptIn(list);
/*当 SqlSeesion 关闭时,会将数据存入到二级缓存*/
sqlSession1.close();
employeeMapper2.selectEmployeeDeptIn(list);
}
当 SqlSeesion 关闭时,会将数据存入到二级缓存
从控制台信息可以看到只执行了一次查询
总结
本章主要讲解了mybatis的动态sql和缓存机制,动态sql作为本章的重点,一定要熟练掌握。关于mybatis的基本内容已经介绍完毕,在后续的学习中,我们将把mybatis和spring框架结合起来,利用spring的事务管理功能更好的实现mybatis框架。