多表查询

简述

多表查询是MyBatis的重要内容。多表查询主要分为连接查询和分次查询,顾名思义,连接查询就是一次性查询完所有的sql语句;分次查询就是分为2次甚至更多次查询sql。从简易程度上讲,连接查询更简便更省事,但是当数据量非常大比如千万级时,连接查询因其存在交叉连接或是回表的操作,使得效率非常低,所以这就产生了分次查询。比如1千万条sql,如果是连接查询,那么查询次数最多可以为1千万×1千万;而如果是分次查询,则有可能降至1千万+1千万。因此,分次查询虽然比较麻烦,但却是必须掌握的。

内容

一对一

  • 连接查询
  • 分次查询

    一对多

  • 连接查询

  • 分次查询

    多对多

  • 连接查询

  • 分次查询

image.png

image.png

image.png

  1. package com.simon;
  2. import com.simon.bean.Student;
  3. import com.simon.bean.User;
  4. import com.simon.bean.UserVO;
  5. import org.apache.ibatis.io.Resources;
  6. import org.apache.ibatis.session.SqlSession;
  7. import org.apache.ibatis.session.SqlSessionFactory;
  8. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  9. import org.junit.AfterClass;
  10. import org.junit.BeforeClass;
  11. import org.junit.Test;
  12. import java.io.IOException;
  13. import java.io.InputStream;
  14. import java.util.ArrayList;
  15. import java.util.HashMap;
  16. import java.util.List;
  17. public class MultiTableTest {
  18. public static SqlSession sqlSession = null;
  19. static Mapper mapper;
  20. @BeforeClass
  21. public static void init() throws IOException {
  22. InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
  23. SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
  24. SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
  25. sqlSession = sqlSessionFactory.openSession();
  26. mapper = sqlSession.getMapper(Mapper.class);
  27. }
  28. @AfterClass
  29. public static void destory(){
  30. sqlSession.commit();
  31. sqlSession.close();
  32. }
  33. //多表查询:
  34. //连接查询:一对一、一对多、多对多
  35. //分次查询:一对一、一对多、多对多
  36. //模板:一对一:用户和用户详情 一对多:班级和学生s 多对多:学生和选课名称
  37. @Test
  38. public void testOne2OneTable(){
  39. User user = mapper.selectAllByUserTableId(8);
  40. System.out.println(user);
  41. }
  42. @Test
  43. public void testOne2OneTable2(){
  44. User user = mapper.selectAllByUserTableId2(8);
  45. System.out.println(user);
  46. }
  47. @Test
  48. public void testOne2MultiTable(){
  49. List<Clazz> clazzs = (List<Clazz>) mapper.selectClazzByClazzTableName("一班");
  50. System.out.println(clazzs);
  51. }
  52. @Test
  53. public void testOne2MultiTable2(){
  54. List<Clazz> clazzs = (List<Clazz>) mapper.selectClazzByClazzTableName2("一班");
  55. System.out.println(clazzs);
  56. }
  57. @Test
  58. public void testMulti2Multi(){
  59. Student student = mapper.selectStudentByStudentName("曹操");
  60. System.out.println(student);
  61. }
  62. @Test
  63. public void testMulti2Multi2(){
  64. Student student = mapper.selectStudentByStudentName2("曹操");
  65. System.out.println(student);
  66. }
  67. }
  1. package com.simon;
  2. import com.simon.bean.Student;
  3. import com.simon.bean.User;
  4. import com.simon.bean.UserVO;
  5. import org.apache.ibatis.annotations.Param;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import java.util.Map;
  9. public interface Mapper {
  10. User selectAllByUserTableId(@Param("id") Integer id);
  11. User selectAllByUserTableId2(@Param("id") Integer id);
  12. List<Clazz> selectClazzByClazzTableName(@Param("clazzName") String clazzName);
  13. List<Clazz> selectClazzByClazzTableName2(@Param("clazzName") String clazzName);
  14. Student selectStudentByStudentName(@Param("studentName") String studentName);
  15. Student selectStudentByStudentName2(@Param("studentName") String studentName);
  16. }
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.simon.Mapper">
  6. <sql id="all_columns">
  7. u.id as id,
  8. u.username as username,
  9. u.password as password,
  10. u.age as age,
  11. ud.id as udid,
  12. ud.user_id as user_id,
  13. ud.pic as pic,
  14. ud.sign as sign
  15. </sql>
  16. <sql id="one2multi_columns">
  17. c.id as id,
  18. c.name as name,
  19. s.id as sid,
  20. s.name as sname,
  21. s.clazzid as clazzid
  22. </sql>
  23. <!--一对一,连接查询-->
  24. <resultMap id="selectUser" type="com.simon.bean.User">
  25. <id column="id" property="id"/>
  26. <result column="username" property="username"/>
  27. <result column="password" property="password"/>
  28. <result column="age" property="age"/>
  29. <association property="userDetail" javaType="com.simon.bean.UserDetail">
  30. <result column="udid" property="id"/>
  31. <result column="user_id" property="userId"/>
  32. <result column="pic" property="pic"/>
  33. <result column="sign" property="sign"/>
  34. </association>
  35. </resultMap>
  36. <select id="selectAllByUserTableId" resultMap="selectUser">
  37. select <include refid="all_columns"/> from user as u inner join user_detail as ud
  38. on u.id = ud.user_id and u.id = #{id};
  39. </select>
  40. <!--一对多,连接查询-->
  41. <resultMap id="selectClazz" type="com.simon.Clazz">
  42. <id column="id" property="id"/>
  43. <result column="name" property="name"/>
  44. <collection property="students" ofType="com.simon.Students">
  45. <result column="sid" property="id"/>
  46. <result column="sname" property="name"/>
  47. <result column="clazzid" property="clazzId"/>
  48. </collection>
  49. </resultMap>
  50. <select id="selectClazzByClazzTableName" resultMap="selectClazz">
  51. SELECT
  52. <include refid="one2multi_columns"/>
  53. FROM
  54. clazz AS c
  55. LEFT JOIN students AS s ON c.id = s.clazzid
  56. AND c.NAME = #{clazzName};
  57. </select>
  58. <!--多对多,连接查询-->
  59. <resultMap id="selectStudent" type="com.simon.bean.Student">
  60. <id column="id" property="id"/>
  61. <result column="name" property="name"/>
  62. <result column="age" property="age"/>
  63. <collection property="course" ofType="com.simon.bean.Course">
  64. <result column="cid" property="id"/>
  65. <result column="cname" property="name"/>
  66. </collection>
  67. </resultMap>
  68. <select id="selectStudentByStudentName" resultMap="selectStudent">
  69. SELECT
  70. s.id AS id,
  71. s.NAME AS NAME,
  72. s.age AS age,
  73. c.id AS cid,
  74. c.NAME AS cname
  75. FROM
  76. student AS s
  77. LEFT JOIN s_c AS sc ON s.id = sc.sid
  78. LEFT JOIN course AS c ON sc.cid = c.id
  79. WHERE
  80. s.NAME = #{studentName};
  81. </select>
  82. <!--一对一,分次查询-->
  83. <resultMap id="selectUser2" type="com.simon.bean.User">
  84. <id column="id" property="id"/>
  85. <result column="username" property="username"/>
  86. <result column="password" property="password"/>
  87. <result column="age" property="age"/>
  88. <association property="userDetail" javaType="com.simon.bean.UserDetail"
  89. select="selectUserDetailById" column="id"/>
  90. </resultMap>
  91. <select id="selectAllByUserTableId2" resultMap="selectUser2">
  92. select id,username,password,age from user where id = #{id}
  93. </select>
  94. <select id="selectUserDetailById" resultType="com.simon.bean.UserDetail">
  95. SELECT
  96. id AS id,
  97. user_id AS uid,
  98. pic AS pic,
  99. sign AS sign
  100. FROM
  101. user_detail
  102. WHERE
  103. user_id = #{uid}
  104. </select>
  105. <!--一对多,分次查询-->
  106. <!--javaType<ofType>-->
  107. <resultMap id="selectClazz2" type="com.simon.Clazz">
  108. <id column="id" property="id"/>
  109. <result column="name" property="name"/>
  110. <collection property="students" javaType="list" column="id2"
  111. select="selectStudentListByClazzId" />
  112. </resultMap>
  113. <select id="selectClazzByClazzTableName2" resultMap="selectClazz2">
  114. select id as id2,name from clazz as c where c.name = #{clazzName}
  115. </select>
  116. <select id="selectStudentListByClazzId" resultType="com.simon.Students">
  117. select id,name,clazzid as clazzId from students where clazzid = #{clazzId}
  118. </select>
  119. <--多对多,分次查询--/>
  120. <resultMap id="selectStudent2" type="com.simon.bean.Student">
  121. <id column="id" property="id"/>
  122. <result column="name" property="name"/>
  123. <result column="age" property="age"/>
  124. <collection property="course" ofType="com.simon.bean.Course" javaType="list"
  125. column="id" select="selectCourseList">
  126. </collection>
  127. </resultMap>
  128. <select id="selectStudentByStudentName2" resultMap="selectStudent2">
  129. SELECT
  130. id,
  131. name,
  132. age
  133. FROM
  134. student
  135. WHERE
  136. name = #{studentName}
  137. </select>
  138. <select id="selectCourseList" resultType="com.simon.bean.Course">
  139. SELECT
  140. c.id AS id,
  141. c.name AS name
  142. FROM
  143. s_c AS sc
  144. LEFT JOIN course AS c ON sc.cid = c.id
  145. WHERE
  146. sc.sid = #{id};
  147. </select>
  148. </mapper>

懒加载

简述

懒加载是为了提高分次查询效率的一种方式。在我们使用分次查询的时候,对于JavaBean的封装可能会分为两次。此时如果我们开启懒加载,那么第二次字段的封装会在我们需要它的时候才会去加载,也就是这时候才会去执行第二次sql查询。
懒加载分为全局懒加载和局部懒加载,这对概念类似于全局变量和局部变量,其用法也类似。懒加载的核心目的就是需要的时候才去加载,不需要的时候就不必去加载,这样就减轻了内存压力。

开启

  • 全局懒加载

mybatis-config.xml文件的settings中,加入:

  • 局部懒加载

在mapper.xml的resultMap的association标签中,加入fatchType属性:
fetchType = lazy 这个表示开启懒加载
fetchType=eager 这个表示关闭懒加载

缓存

简述

缓存类似于备份的概念。根据缓存级别的不同,分为一级缓存和二级缓存。一级缓存是sqlSession级别的,即会话级别,一旦会话结束,缓存就失效;二级缓存是namespace级别的,对应Java就是类,除非新建一个类,否则缓存就会一直存在。客户端访问的时候,先去二级缓存里面找,没找到再去一级缓存找,一级缓存也没找到,就去Mysql数据库里找。
image.png

一级缓存

image.png
image.png
总结,走一级缓存的情况:
同一个sqlSession,mapper可相同,也可不相同,同一个参数,都查询完再提交
不走一级缓存的情况:

  • 不同的sqlSession
  • 同一个sqlSession,不同的参数
  • 不是查询语句

    二级缓存

    开启

    1. <!--二级缓存开启-->
    2. <setting name="cacheEnabled" value="true" />

    序列化ID

    需要去给我们需要缓存的JavaBean实现序列化接口,生成序列化id
    开启idea设置
    MyBatis(下) - 图7image-20210402155823622.png
    MyBatis(下) - 图9
    MyBatis(下) - 图10
  1. 在我们需要开启二级缓存的mapper.xml中配置以下标签
    MyBatis(下) - 图11 image.png

使用

  1. // 测试二级缓存
  2. // Cache Hit Ratio [com.simon.mapper.UserMapper]: 0.0 这个表示二级缓存已经开启,但是没有命中
  3. @Test
  4. public void testSelectUserById5(){
  5. SqlSession sqlSession1 = sqlSessionFactory.openSession();
  6. SqlSession sqlSession2 = sqlSessionFactory.openSession();
  7. SqlSession sqlSession3 = sqlSessionFactory.openSession();
  8. SqlSession sqlSession4 = sqlSessionFactory.openSession();
  9. UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
  10. UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
  11. UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
  12. UserMapper userMapper4 = sqlSession4.getMapper(UserMapper.class);
  13. User user1 = userMapper1.selectUserById(10); // 执行查询
  14. sqlSession1.commit(); // 把结果放入二级缓存
  15. /**
  16. * Cache Hit Ratio [com.simon.mapper.UserMapper]: 0.5
  17. * Cache Hit Ratio [com.simon.mapper.UserMapper]: 0.6666666666666666
  18. * Cache Hit Ratio [com.simon.mapper.UserMapper]: 0.75
  19. *
  20. */
  21. User user2 = userMapper2.selectUserById(10);
  22. User user3 = userMapper3.selectUserById(10);
  23. User user4 = userMapper4.selectUserById(10);
  24. System.out.println(user1);
  25. System.out.println(user2);
  26. System.out.println(user3);
  27. System.out.println(user4);
  28. }