多表查询
简述
多表查询是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;
@BeforeClass
public 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);
}
@AfterClass
public static void destory(){
sqlSession.commit();
sqlSession.close();
}
//多表查询:
//连接查询:一对一、一对多、多对多
//分次查询:一对一、一对多、多对多
//模板:一对一:用户和用户详情 一对多:班级和学生s 多对多:学生和选课名称
@Test
public void testOne2OneTable(){
User user = mapper.selectAllByUserTableId(8);
System.out.println(user);
}
@Test
public void testOne2OneTable2(){
User user = mapper.selectAllByUserTableId2(8);
System.out.println(user);
}
@Test
public void testOne2MultiTable(){
List<Clazz> clazzs = (List<Clazz>) mapper.selectClazzByClazzTableName("一班");
System.out.println(clazzs);
}
@Test
public void testOne2MultiTable2(){
List<Clazz> clazzs = (List<Clazz>) mapper.selectClazzByClazzTableName2("一班");
System.out.println(clazzs);
}
@Test
public void testMulti2Multi(){
Student student = mapper.selectStudentByStudentName("曹操");
System.out.println(student);
}
@Test
public 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 mapper
PUBLIC "-//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 ud
on 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"/>
FROM
clazz AS c
LEFT JOIN students AS s ON c.id = s.clazzid
AND 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">
SELECT
s.id AS id,
s.NAME AS NAME,
s.age AS age,
c.id AS cid,
c.NAME AS cname
FROM
student AS s
LEFT JOIN s_c AS sc ON s.id = sc.sid
LEFT JOIN course AS c ON sc.cid = c.id
WHERE
s.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">
SELECT
id AS id,
user_id AS uid,
pic AS pic,
sign AS sign
FROM
user_detail
WHERE
user_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">
SELECT
id,
name,
age
FROM
student
WHERE
name = #{studentName}
</select>
<select id="selectCourseList" resultType="com.simon.bean.Course">
SELECT
c.id AS id,
c.name AS name
FROM
s_c AS sc
LEFT JOIN course AS c ON sc.cid = c.id
WHERE
sc.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 这个表示二级缓存已经开启,但是没有命中
@Test
public 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);
}