第四章、MyBatis的关联映射和缓存机制
在实际开发中,对数据库的操作常常会涉及到多张表,针对多表之间的操作,
MyBatis提供了关联映射,通过关联映射可以很好地处理
表与表、对象与对象之间的关联关系。
实际开发中经常需要合理地利用MyBatis缓存来加快数据库查询,
进而有效地提升数据库性能。
在关系型数据库中,表与表之间存在着三种关联映射关系,
分别为一对一关系、一对多关系和多对多关系。
一、映射关系
java对象通过类表达表之间关系
数据表之间的关系实质上描述的是数据之间的关系,除了数据表,
在Java中,还可以通过对象来描述数据之间的关系。
通过Java对象描述数据之间的关系,
其实就是使对象的属性与另一个对象的属性相互关联。
二、一对一关系
在MyBatis中,通过association元素来处理一对一关联关系。
association元素提供了一系列属性用于维护数据表之间的关系。
association元素是resultMap元素的子元素,它有两种配置方式,
- 嵌套查询方式
- 嵌套结果方式
下面对这两种配置方式分别进行介绍。
嵌套查询是指通过执行另外一条SQL映射语句来返回预期的复杂类型。
在使用MyBatis嵌套查询方式进行MyBatis关联映射查询时,
使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。
MyBatis默认没有开启延迟加载,需要在mybatis-config.xml中的<settings>元素内进行配置。
<settings>
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 将积极加载改为消息加载,即按需加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
嵌套结果是使用嵌套结果映射来处理重复的联合结果的子集。
例子
personMapper.xml
<select id="findPersonById" parameterType="Integer"
resultMap="IdCardWithPersonResult">
SELECT * from tb_person where id=#{id}
</select>
<resultMap type="Person" id="IdCardWithPersonResult">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<!-- 一对一:association使用select属性引入另外一条SQL语句 -->
<association property="card" column="card_id" javaType="IdCard"
select="mapper.IdCardMapper.findCodeById"/>
</resultMap>
IDCardMapper.xml
<mapper namespace="mapper.IdCardMapper">
<!-- 根据id查询证件信息 -->
<select id="findCodeById" parameterType="Integer" resultType="IdCard">
SELECT * from tb_idcard where id=#{id}
</select>
</mapper>
测试类
@Test
public void findPersonByIdTest() {
// 1、通过工具类获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
// 2.使用MyBatis嵌套查询的方式查询id为1的人的信息
Person person = session.selectOne("mapper."
+ "PersonMapper.findPersonById", 1);
// 3、输出查询结果信息
System.out.println(person);
// 4、关闭SqlSession
session.close();
}
三、一对多关系
能够使用<collection>元素处理一对多关联关系
在MyBatis中,通过<collection>元素来处理一对多关联关系。
<collection>元素的属性大部分与<association>元素相同,
但其还包含一个特殊属性ofType。ofType属性与javaType属性对应,
它用于指定实体类对象中集合类属性所包含的元素的类型,
<collection>元素是<resultMap>元素的子元素
四、多对多关系
在数据库中,在两个表有多对多关系,使用中间表,来辅助建立多对多关系。
五、Mybatis缓存
1.一级缓存
MyBatis的一级缓存是SqlSession级别的缓存。
如果同一个SqlSession对象多次执行完全相同的SQL语句时,
在第一次执行完成后,MyBatis会将查询结果写入到一级缓存中,
此后,如果程序没有执行插入、更新、删除操作,
当第二次执行相同的查询语句时,MyBatis会直接读取一级缓存中的数据,
而不用再去数据库查询,从而提高了数据库的查询效率。
当程序对数据库执行了插入、更新、删除操作,
MyBatis会清空一级缓存中的内容以防止程序误读。
2.二级缓存
MyBatis的二级缓存需要手动开启
相同的Mapper类,相同的SQL语句,如果SqlSession不同,则两个SqlSession查询数据库时,会查询数据库两次,这样也会降低数据库的查询效率。为了解决这个问题,就需要用到MyBatis的二级缓存。MyBatis的二级缓存是Mapper级别的缓存,与一级缓存相比,二级缓存的范围更大,多个SqlSession可以共用二级缓存,并且二级缓存可以自定义缓存资源。
多个SqlSession对象使用同一个Mapper的相同查询语句去操作数据库,
在第一个SqlSession对象执行完后,MyBatis会将查询结果写入二级缓存,
此后,如果程序没有执行插入、更新、删除操作,
当第二个SqlSession对象执行相同的查询语句时,MyBatis会直接读取二级缓存中的数据。
(1)映射文件中所有select语句将会被缓存。
(2)映射文件中的所有insert、update和delete语句都会刷新缓存。
(3)缓存会使用LRU算法回收。
(4)没有刷新间隔,缓存不会以任何时间顺序来刷新。
(5)缓存会存储列表集合或对象的1024个引用。
(6)缓存是可读/可写的缓存,这意味着对象检索不是共享的,
缓存可以安全的被调用者修改,而不干扰其他调用者或线程所做的潜在修改。