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



package com.simon;import com.simon.bean.Student;import com.simon.bean.User;import com.simon.bean.UserVO;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.AfterClass;import org.junit.BeforeClass;import org.junit.Test;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.HashMap;import java.util.List;public class MultiTableTest {public static SqlSession sqlSession = null;static Mapper mapper;@BeforeClasspublic static void init() throws IOException {InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);sqlSession = sqlSessionFactory.openSession();mapper = sqlSession.getMapper(Mapper.class);}@AfterClasspublic static void destory(){sqlSession.commit();sqlSession.close();}//多表查询://连接查询:一对一、一对多、多对多//分次查询:一对一、一对多、多对多//模板:一对一:用户和用户详情 一对多:班级和学生s 多对多:学生和选课名称@Testpublic void testOne2OneTable(){User user = mapper.selectAllByUserTableId(8);System.out.println(user);}@Testpublic void testOne2OneTable2(){User user = mapper.selectAllByUserTableId2(8);System.out.println(user);}@Testpublic void testOne2MultiTable(){List<Clazz> clazzs = (List<Clazz>) mapper.selectClazzByClazzTableName("一班");System.out.println(clazzs);}@Testpublic void testOne2MultiTable2(){List<Clazz> clazzs = (List<Clazz>) mapper.selectClazzByClazzTableName2("一班");System.out.println(clazzs);}@Testpublic void testMulti2Multi(){Student student = mapper.selectStudentByStudentName("曹操");System.out.println(student);}@Testpublic void testMulti2Multi2(){Student student = mapper.selectStudentByStudentName2("曹操");System.out.println(student);}}
package com.simon;import com.simon.bean.Student;import com.simon.bean.User;import com.simon.bean.UserVO;import org.apache.ibatis.annotations.Param;import java.util.ArrayList;import java.util.List;import java.util.Map;public interface Mapper {User selectAllByUserTableId(@Param("id") Integer id);User selectAllByUserTableId2(@Param("id") Integer id);List<Clazz> selectClazzByClazzTableName(@Param("clazzName") String clazzName);List<Clazz> selectClazzByClazzTableName2(@Param("clazzName") String clazzName);Student selectStudentByStudentName(@Param("studentName") String studentName);Student selectStudentByStudentName2(@Param("studentName") String studentName);}
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.simon.Mapper"><sql id="all_columns">u.id as id,u.username as username,u.password as password,u.age as age,ud.id as udid,ud.user_id as user_id,ud.pic as pic,ud.sign as sign</sql><sql id="one2multi_columns">c.id as id,c.name as name,s.id as sid,s.name as sname,s.clazzid as clazzid</sql><!--一对一,连接查询--><resultMap id="selectUser" type="com.simon.bean.User"><id column="id" property="id"/><result column="username" property="username"/><result column="password" property="password"/><result column="age" property="age"/><association property="userDetail" javaType="com.simon.bean.UserDetail"><result column="udid" property="id"/><result column="user_id" property="userId"/><result column="pic" property="pic"/><result column="sign" property="sign"/></association></resultMap><select id="selectAllByUserTableId" resultMap="selectUser">select <include refid="all_columns"/> from user as u inner join user_detail as udon u.id = ud.user_id and u.id = #{id};</select><!--一对多,连接查询--><resultMap id="selectClazz" type="com.simon.Clazz"><id column="id" property="id"/><result column="name" property="name"/><collection property="students" ofType="com.simon.Students"><result column="sid" property="id"/><result column="sname" property="name"/><result column="clazzid" property="clazzId"/></collection></resultMap><select id="selectClazzByClazzTableName" resultMap="selectClazz">SELECT<include refid="one2multi_columns"/>FROMclazz AS cLEFT JOIN students AS s ON c.id = s.clazzidAND c.NAME = #{clazzName};</select><!--多对多,连接查询--><resultMap id="selectStudent" type="com.simon.bean.Student"><id column="id" property="id"/><result column="name" property="name"/><result column="age" property="age"/><collection property="course" ofType="com.simon.bean.Course"><result column="cid" property="id"/><result column="cname" property="name"/></collection></resultMap><select id="selectStudentByStudentName" resultMap="selectStudent">SELECTs.id AS id,s.NAME AS NAME,s.age AS age,c.id AS cid,c.NAME AS cnameFROMstudent AS sLEFT JOIN s_c AS sc ON s.id = sc.sidLEFT JOIN course AS c ON sc.cid = c.idWHEREs.NAME = #{studentName};</select><!--一对一,分次查询--><resultMap id="selectUser2" type="com.simon.bean.User"><id column="id" property="id"/><result column="username" property="username"/><result column="password" property="password"/><result column="age" property="age"/><association property="userDetail" javaType="com.simon.bean.UserDetail"select="selectUserDetailById" column="id"/></resultMap><select id="selectAllByUserTableId2" resultMap="selectUser2">select id,username,password,age from user where id = #{id}</select><select id="selectUserDetailById" resultType="com.simon.bean.UserDetail">SELECTid AS id,user_id AS uid,pic AS pic,sign AS signFROMuser_detailWHEREuser_id = #{uid}</select><!--一对多,分次查询--><!--javaType<ofType>--><resultMap id="selectClazz2" type="com.simon.Clazz"><id column="id" property="id"/><result column="name" property="name"/><collection property="students" javaType="list" column="id2"select="selectStudentListByClazzId" /></resultMap><select id="selectClazzByClazzTableName2" resultMap="selectClazz2">select id as id2,name from clazz as c where c.name = #{clazzName}</select><select id="selectStudentListByClazzId" resultType="com.simon.Students">select id,name,clazzid as clazzId from students where clazzid = #{clazzId}</select><--多对多,分次查询--/><resultMap id="selectStudent2" type="com.simon.bean.Student"><id column="id" property="id"/><result column="name" property="name"/><result column="age" property="age"/><collection property="course" ofType="com.simon.bean.Course" javaType="list"column="id" select="selectCourseList"></collection></resultMap><select id="selectStudentByStudentName2" resultMap="selectStudent2">SELECTid,name,ageFROMstudentWHEREname = #{studentName}</select><select id="selectCourseList" resultType="com.simon.bean.Course">SELECTc.id AS id,c.name AS nameFROMs_c AS scLEFT JOIN course AS c ON sc.cid = c.idWHEREsc.sid = #{id};</select></mapper>
懒加载
简述
懒加载是为了提高分次查询效率的一种方式。在我们使用分次查询的时候,对于JavaBean的封装可能会分为两次。此时如果我们开启懒加载,那么第二次字段的封装会在我们需要它的时候才会去加载,也就是这时候才会去执行第二次sql查询。
懒加载分为全局懒加载和局部懒加载,这对概念类似于全局变量和局部变量,其用法也类似。懒加载的核心目的就是需要的时候才去加载,不需要的时候就不必去加载,这样就减轻了内存压力。
开启
- 全局懒加载
mybatis-config.xml文件的settings中,加入:
- 局部懒加载
在mapper.xml的resultMap的association标签中,加入fatchType属性:
fetchType = lazy 这个表示开启懒加载
fetchType=eager 这个表示关闭懒加载
缓存
简述
缓存类似于备份的概念。根据缓存级别的不同,分为一级缓存和二级缓存。一级缓存是sqlSession级别的,即会话级别,一旦会话结束,缓存就失效;二级缓存是namespace级别的,对应Java就是类,除非新建一个类,否则缓存就会一直存在。客户端访问的时候,先去二级缓存里面找,没找到再去一级缓存找,一级缓存也没找到,就去Mysql数据库里找。
一级缓存


总结,走一级缓存的情况:
同一个sqlSession,mapper可相同,也可不相同,同一个参数,都查询完再提交
不走一级缓存的情况:
- 不同的sqlSession
- 同一个sqlSession,不同的参数
- 不是查询语句
二级缓存
开启
<!--二级缓存开启--><setting name="cacheEnabled" value="true" />
序列化ID
需要去给我们需要缓存的JavaBean实现序列化接口,生成序列化id
开启idea设置


- 在我们需要开启二级缓存的mapper.xml中配置以下标签

使用
// 测试二级缓存// Cache Hit Ratio [com.simon.mapper.UserMapper]: 0.0 这个表示二级缓存已经开启,但是没有命中@Testpublic void testSelectUserById5(){SqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();SqlSession sqlSession3 = sqlSessionFactory.openSession();SqlSession sqlSession4 = sqlSessionFactory.openSession();UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);UserMapper userMapper4 = sqlSession4.getMapper(UserMapper.class);User user1 = userMapper1.selectUserById(10); // 执行查询sqlSession1.commit(); // 把结果放入二级缓存/*** Cache Hit Ratio [com.simon.mapper.UserMapper]: 0.5* Cache Hit Ratio [com.simon.mapper.UserMapper]: 0.6666666666666666* Cache Hit Ratio [com.simon.mapper.UserMapper]: 0.75**/User user2 = userMapper2.selectUserById(10);User user3 = userMapper3.selectUserById(10);User user4 = userMapper4.selectUserById(10);System.out.println(user1);System.out.println(user2);System.out.println(user3);System.out.println(user4);}
