MyBatis之关联查询和缓存
Posted 一宿君
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis之关联查询和缓存相关的知识,希望对你有一定的参考价值。
关联查询分为
- 一对一
- 一对多
- 多对一
- 多对多
resultMap属性
- id:resultMap的唯一标识
- type:Java实体类类型
resultMap子元素
- id:一般对应数据库中该行的主键id,设置此项可提高MyBatis性能
- result:映射到JavaBean的某个“简单类型”属性
- association:映射到JavaBean的某个“复杂类型”属性,比如JavaBean类
- collection:映射到JavaBean的某个“复杂类型”属性,比如集合
association
- 复杂的类型关联,一对一,多对一
- 内部嵌套:映射一个嵌套JavaBean属性
- 属性
property:映射数据库列的实体对象的属性
javaType:完整Java类名或别名
resultMap:引用外部resultMap - 子元素
id
result- property:映射数据库列的实体对象的属性
- column:数据库列名或者别名
4.1 一对一(一个qq用户qqUser对应一个 个人信息baseInfo)
- 实体类
- QQUserMapper.xml
<?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是命名空间,要与对应的接口的路径保持一致(如果没有创建该接口,MyBatis在内部编译时会自动创建)--> <mapper namespace="com.ebuy.dao.QQUserMapper"> <resultMap id="qqUserMap" type="com.ebuy.pojo.QQUser"> <result property="qqid" column="qqid"/> <result property="password" column="password"/> <result property="lastlogtime" column="lastlogtime"/> <result property="onlines" column="onlines"/> <result property="levels" column="levels"/> <!--关联表 一对一,一个qq号账户对应一个 个人用户信息--> <association property="baseInfo" javaType="com.ebuy.pojo.BaseInfo"> <id property="qqid" column="qqid"/> <result property="nickname" column="nickname"/> <result property="sex" column="sex"/> <result property="age" column="age"/> <result property="province" column="province"/> <result property="city" column="city"/> <result property="address" column="address"/> <result property="phone" column="phone"/> </association> </resultMap> <!--关联查询所有用户信息——一对一--> <select id="selectQQUserAll" resultMap="qqUserMap"> select * from qquser a,baseinfo b where a.qqid = b.qqid </select> </mapper>
- QQUserMapper接口
/** * @author 一宿君(CSDN : qq_52596258) * @date 2021-07-07 10:08:36 */ public interface QQUserMapper { /** * * @return */ List<QQUser> selectQQUserAll(); }
- QQUserMapperTest
/** * 利用接口引用,调用mapper映射文件中的方法 * @throws IOException */ @Test public void selectQQUserAll() throws IOException { SqlSession sqlSession = MyBatisUtil.createSqlSession(); QQUserMapper qqUserMapper = sqlSession.getMapper(QQUserMapper.class); List<QQUser> qqUserList = qqUserMapper.selectQQUserAll(); for(QQUser qqUser:qqUserList){ System.out.println(qqUser); } MyBatisUtil.closeSqlSession(sqlSession); }
4.2 多对一(多个用户SystemUser对应一个角色SystemRole),结构上与一对一的形式一致
- SystemUser
- SystemUserMapper.xml
<!--namespace是命名空间,要与对应的接口的路径保持一致(如果没有创建该接口,MyBatis在内部编译时会自动创建)--> <mapper namespace="com.ebuy.dao.SystemUserMapper"> <resultMap id="userMap" type="com.ebuy.pojo.SystemUser"> <result property="userinfouid" column="userinfo_uid"/> <result property="userinfologinid" column="userinfo_loginid"/> <result property="userinfoname" column="userinfo_name"/> <result property="userinfo_password" column="userinfo_password"/> <result property="userinfo_sex" column="userinfo_sex"/> <result property="userinfo_email" column="userinfo_email"/> <result property="userinfo_mobile" column="userinfo_mobile"/> <result property="userinfo_status" column="userinfo_status"/> <!--<result property="userinfo_roleid" column="userinfo_roleid"/> <result property="userinfo_rolename" column="role_name"/>--> <!--关联查询,一对一--> <association property="systemRole" javaType="com.ebuy.pojo.SystemRole"> <!--关联查询中的唯一标识--> <id property="role_id" column="userinfo_roleid"/> <result property="role_name" column="role_name"/> <result property="role_code" column="role_code"/> <result property="role_description" column="role_description"/> </association> </resultMap> <!--关联查询表system_userinfo和表system_role,查询结果是多对一,也就是多个用户对应一个角色--> <select id="selectUserAll" resultMap="userMap"> /*select * from system_userinfo*/ select a.*,b.role_name from system_userinfo a,system_role b where a.userinfo_roleid = b.role_id </select> </mapper>
- SystemUSerMapper接口
/** * 关联查询(多对一) * @return */ List<SystemUser> selectUserAllByAssociation();
- SysteUserMapperTest
@Test public void selectUserAllByAssociation(){ SqlSession sqlSession = MyBatisUtil.createSqlSession(); SystemUserMapper systemUserMapper = sqlSession.getMapper(SystemUserMapper.class); List<SystemUser> systemUserList = systemUserMapper.selectUserAllByAssociation(); for(SystemUser s:systemUserList){ System.out.println(s); } MyBatisUtil.closeSqlSession(sqlSession); }
Collection
- 复杂类型集合,一对多
- 内部嵌套:映射一个嵌套结果集到一个列表
- 属性
property:映射数据库列的实体对象的属性
ofType:完整Java类名或者别名(集合泛型中所包含的类型)
resultMap:引用外部resultMap - 子元素
id
result- property:映射数据库列的实体对象的属性
- column:数据库列名或者别名
- resultMap自动映射(autoMappingBehavior)的三个匹配级别
NONE:禁止自动匹配
PARTIAL(默认):自动匹配所有属性,内部嵌套除外
FULL:自动匹配所有(前提实体类属性和数据库列名保持一致)
4.3 一对多(一个角色SystemRole对应多个用户SystemUser)
- SystemRole
- SystemRoleMapper.xml
<!--namespace是命名空间,要与对应的接口的路径保持一致(如果没有创建该接口,MyBatis在内部编译时会自动创建)--> <mapper namespace="com.ebuy.dao.SystemRoleMapper"> <resultMap id="roleMap" type="com.ebuy.pojo.SystemRole"> <id property="role_id" column="role_id"/> <result property="role_name" column="role_name"/> <result property="role_code" column="role_code"/> <result property="role_description" column="role_description"/> <!--关联查询 多对一 --> <collection property="userInfoList" ofType="com.ebuy.pojo.SystemUser"> <result property="userinfouid" column="userinfo_uid"/> <result property="userinfologinid" column="userinfo_loginid"/> <result property="userinfoname" column="userinfo_name"/> <result property="userinfo_password" column="userinfo_password"/> <result property="userinfo_sex" column="userinfo_sex"/> <result property="userinfo_email" column="userinfo_email"/> <result property="userinfo_mobile" column="userinfo_mobile"/> <result property="userinfo_status" column="userinfo_status"/> </collection> </resultMap> <!--关联查询查询system_role表和system_userinfo--> <select id="selectRoleAllByCollection" resultMap="roleMap"> select * from system_role a,system_userinfo b where a.role_id = b.userinfo_roleid </select> </mapper>
- SystemRoleMapper接口
/** * 关联查询查询system_role表和system_userinfo * @return */ List<SystemRole> selectRoleAllByCollection();
- SystemRoleMapperTest
/** * 利用接口引用,调用mapper映射文件中的方法 * @throws IOException */ @Test public void selectRoleAllByCollection(){ SqlSession sqlSession = MyBatisUtil.createSqlSession(); SystemRoleMapper systemRoleMapper = sqlSession.getMapper(SystemRoleMapper.class); List<SystemRole> systemRoleList = systemRoleMapper.selectRoleAllByCollection(); for(SystemRole s:systemRoleList){ System.out.println(s.getRole_name() + ":"); for (SystemUser systemUser:s.getUserInfoList()){ System.out.println("\\t" + systemUser); } } MyBatisUtil.closeSqlSession(sqlSession); }
resultMap自动映射(autoMappingBehavior),可在mybatis-conf.xml配置文件中设置
- 示例1
- 示例2
上述是在mybatis-conf.xml配置文件中配置的自动映射,还可以在mapper映射文件中配置自动映射(作用于局部mapper)
- 示例3
MyBatis缓存
- 一级缓存
- 二级缓存
- 二级缓存的配置
- MyBatis的全局cache配置
- 在Mapper XML文件中设置缓存,默认情况下是没有开启缓存的
- 在Mapper XML文件配置支持cache后,如果需要对个别查询进行调整,可以单独设置cache
一级缓存(第一次查询出的数据(默认)放入到了缓存中)
- SystemUserMapperTest
@Test public void count2() throws IOException { SqlSession sqlSession = MyBatisUtil.createSqlSession(); SystemUserMapper systemUserMapper = sqlSession.getMapper(SystemUserMapper.class); //第一次查询 System.out.println(systemUserMapper.count()); /** * 第二次查询(查询到的是一级缓存中的数据,也就是第一次查询出的数据放入到了缓存中) * 第二次查询并不会再次创建sqlSession,也就是不会执行SQL语句操作数据库查询 */ System.out.println(systemUserMapper.count()); MyBatisUtil.closeSqlSession(sqlSession); }
一级缓存(改进,执行两次sql后关闭sqlSession,再次开启sqlSession)
-
SystemUserMapper
@Test public void count2() throws IOException { SqlSession sqlSession = MyBatisUtil.createSqlSession(); SystemUserMapper systemUserMapper = sqlSession.getMapper(SystemUserMapper.class); System.out.println(systemUserMapper.count());//第一次查询 /** * 第二次查询(查询到的是一级缓存中的数据,也就是第一次查询出的数据放入到了一级缓存中) * 第二次查询并不会再次创建sqlSession,也就是不会执行SQL语句操作数据库查询 */ System.out.println(systemUserMapper.count());//第二次查询 MyBatisUtil.closeSqlSession(sqlSession);//关闭sqlSession sqlSession = MyBatisUtil.createSqlSession(); systemUserMapper = sqlSession.getMapper(SystemUserMapper.class); System.out.println(systemUserMapper.count());//第三次查询 /** * 同理 * 第四次查询(查询到的是一级缓存中的数据,也就是第三次查询出的数据放入到了一级缓存中) * 第四次查询并不会再次创建sqlSession,也就是不会执行SQL语句操作数据库查询 */ System.out.println(systemUserMapper.count());//第四次查询 MyBatisUtil.closeSqlSession(sqlSession); }
会发现上述执行了两次sql!上述每次开启sqlSession后的第一次不同的SQL查询都会将结果存入到缓存中,一级缓存只要sqlSession关闭就会一直存在,这样对于内存负荷量比较大,而且不利于频繁更新的数据要求。
二级缓存(可设置时效性,解决一级缓存会一直存在的弊端)
-
首先开启二级缓存
-
在相关映射文件中设置时效性和每次最大的缓存记录数
<cache eviction="FIFO" flushInterval="5000" size="512" readOnly="true"/>
-
SystemRoleMapperTest
@Test public void selectRoleAllByCollection() throws InterruptedException { SqlSession sqlSession = MyBatisUtil.createSqlSession();//开启sqlSession SystemRoleMapper systemRoleMapper = sqlSession.getMapper(SystemRoleMapper.class); List<SystemRole> systemRoleList1 = systemRoleMapper.selectRoleAllByCollection(); for(SystemRole s:systemRoleList1){ System.out.println(s.getRole_name() + ":"); for (SystemUser systemUser:s.getUserInfoList()){ System.out.println("\\t" + systemUser); } } MyBatisUtil.closeSqlSession(sqlSession);//关闭sqlSession /** * 循环8次,注意二级缓存设置的有效期为5秒 */ for (int i = 1; i <= 8; i++) { sqlSession = MyBatisUtil.createSqlSession();//开启sqlSession systemRoleMapper = sqlSession.getMapper(SystemRoleMapper.class); System.out.println("第" + i + "次查询---------------------------------"); List<SystemRole> systemRoleList2 = systemRoleMapper.selectRoleAllByCollection(); for(SystemRole s:systemRoleList2){ System.out.println(s.getRole_name() + ":"); for (SystemUser systemUser:s.getUserInfoList()){ System.out.println("\\t" + systemUser); } } Thread.sleep(1000);//没循环一次线程等待1秒 MyBatisUtil.closeSqlSession(sqlSession);//关闭sqlSession } }
-
控制台结果显示:
-
初始查询
-
第1次循环查询
-
第2次循环查询
-
第3次循环查询
-
第4次循环查询
-
第5次循环查询
-
第6次循环查询
-
第7次循环查询
-
第8次循环查询
以上是关于MyBatis之关联查询和缓存的主要内容,如果未能解决你的问题,请参考以下文章
mybatis基础系列——关联查询延迟加载一级缓存与二级缓存