MyBatis框架(二)

一、基于代理Dao实现CRUD操作

1. 根据ID查询用户信息

(1)在持久层接口中添加 findById 方法:

User findById(Integer userId);

(2)在映射文件中配置:

<!-- 根据 id 查询 --> 
<select id="findById" resultType="com.itheima.domain.User" parameterType="int">
	select * from user where id = #{uid}
</select>

​ resultType 属性:用于指定结果集的类型。

​ parameterType 属性:用于指定传入参数的类型。

​ #{uid}:用来接收传入的参数。

(3)在测试类中添加测试方法:

public class MybastisCRUDTest {
    private InputStream in ;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IUserDao userDao;
    @Test
    public void testFindOne() {
        //6.执行操作
        User user = userDao.findById(41);
        System.out.println(user);
    }
    @Before//在测试方法执行之前执行
    public void init()throws Exception {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建构建者对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //3.创建 SqlSession 工厂对象
        factory = builder.build(in);
        //4.创建 SqlSession 对象
        session = factory.openSession();
        //5.创建 Dao 的代理对象
        userDao = session.getMapper(IUserDao.class);
    }
    @After//在测试方法执行完成之后执行
	public void destroy() throws Exception{
        session.commit();
        //7.释放资源
        session.close();
        in.close();
	} 
}

2. 新增用户信息

(1)在持久层接口中添加插入方法:

/**
* 保存用户
* @param user
* @return 影响数据库记录的行数
*/
int insertUser(User user);

(2)在映射文件中配置:

<!-- 新增用户--> 
<insert id="insertUser" parameterType="com.itheima.domain.User">
	insert into user(username,birthday,sex,address) values(#{username},#{birthday},#	{sex},#{address})
</insert>

(3)在测试类中添加测试方法:

@Test
public void testSave(){
    User user = new User();
    user.setUsername("张三");
    user.setAddress("北京市顺义区");
    user.setSex("男");
    user.setBirthday(new Date());
    System.out.println("插入操作之前:"+user);
    // 执行插入方法
    userDao.insertUser(user);
    System.out.println("插入操作之后:"+user);
}
/*
	打开 MySQL 数据库发现并没有添加任何记录,原因是什么?这一点和 JDBC 是一样的,我们在实现增删改时一	  定要去控制事务的提交,那么在 MyBatis 中如何控制事务提交呢?可以使用:session.commit();来实现事务提交。
*/
@After//在测试方法执行完成之后执行
public void destroy() throws Exception{
    session.commit();
    // 释放资源
    session.close();
    in.close();
}

3. 更新用户信息

(1)在持久层接口中添加更新方法:

/**
* 更新用户
* @param user
* @return 影响数据库记录的行数
*/
int updateUser(User user);

(2)在映射文件中配置:

<!-- 更新用户 --> 
<update id="updateUser" parameterType="com.itheima.domain.User">
	update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#		{address} where id=#{id}
</update>

(3)在测试类中添加测试方法:

@Test
public void testUpdateUser() throws Exception{
    //1.根据 id 查询
    User user = userDao.findById(52);
    //2.更新操作
    user.setAddress("北京市顺义区");
    int res = userDao.updateUser(user);
    System.out.println(res);
}

4. 删除用户信息

(1)在持久层接口中添加删除方法:

/**
* 根据 id 删除用户
* @param userId
* @return
*/
int deleteUser(Integer userId);

(2)在映射文件中配置:

<!-- 删除用户 --> 
<delete id="deleteUser" parameterType="java.lang.Integer">
	delete from user where id = #{uid}
</delete>

(3)在测试类中添加测试方法:

@Test
public void testDeleteUser() throws Exception {
    int res = userDao.deleteUser(52);
    System.out.println(res);
}

5. 模糊查询

(1)在持久层接口中添加模糊查询方法:

/**
* 根据名称模糊查询
* @param username
* @return
*/
List<User> findByName(String username);

(2)在映射文件中配置:

<!-- 根据名称模糊查询 --> 
<select id="findByName" resultType="com.itheima.domain.User" parameterType="String">
	select * from user where username like #{username}
</select>

(3)在测试类中添加测试方法:

@Test
public void testFindByName(){
    List<User> users = userDao.findByName("%王%");
    for(User user : users){
    	System.out.println(user);
    }
}

6. 使用聚合函数查询

(1)在持久层接口中添加查询方法:

/**
* 查询总记录条数
* @return
*/
int findTotal();

(2)在映射文件中配置:

<!-- 查询总记录条数 --> 
<select id="findTotal" resultType="int">
	select count(*) from user;
</select>

(3)在测试类中添加测试方法:

@Test
public void testFindTotal() throws Exception {
    int res = userDao.findTotal();
    System.out.println(res);
}

二、MyBatis的动态 SQL 语句

1. < if >标签

​ 我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 username 不为空时可以根据 username 查询,如果 address 不为空时还要加入 address 作为查询条件。这种情况在我们的多条件组合查询中经常会碰到。

(1)持久层Dao接口:

/**
* 根据用户信息,查询用户列表
* @param user
* @return
*/
List<User> findByUser(User user);

(2)映射配置文件:

<select id="findByUser" resultType="user" parameterType="user">
    select * from user where 1=1
    <if test="username != null and username != '' ">
    	and username like #{username}
    </if> 
    <if test="address != null">
    	and address like #{address}
    </if>
</select>

【注】< if >标签的 test 属性中写的是对象的属性名。

(3)测试:

@Test
public void testFindByUser() {
    User u = new User();
    u.setUsername("%王%");
    u.setAddress("%顺义%");
    List<User> users = userDao.findByUser(u);
    for(User user : users) {
    	System.out.println(user);
	} 
}

2. < where >标签

​ 为了简化上面 where 1=1 的条件拼装,我们可以采用< where >标签来简化开发。

映射配置文件:

<!-- 根据用户信息查询 --> 
<select id="findByUser" resultType="user" parameterType="user"> 
	<include refid="defaultSql"></include> 
    <where> 
        <if test="username != null and username != '' ">
            and username like #{username}
        </if> 
        <if test="address != null">
            and address like #{address}
        </if>
    </where>
</select>

3. < foreach >标签

(0)需求:

​ 传入多个 id 查询用户信息,用下边两个 SQL 实现:

SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16)

SELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,89,16)

​ 这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。那么我们将如何进行参数的传递呢?

(1)在 QueryVo 中加入一个 List 集合用于封装参数:

public class QueryVo implements Serializable {
	private List<Integer> ids;
	public List<Integer> getIds() {
		return ids; 
	}
	public void setIds(List<Integer> ids) {
		this.ids = ids; 
	} 
}

(2)持久层Dao接口:

/**
* 根据 id 集合查询用户
* @param vo
* @return
*/
List<User> findInIds(QueryVo vo);

(3)映射配置文件:

<!-- 查询所有 id 在 id 集合之中的用户 --> 
<select id="findInIds" resultType="user" parameterType="queryvo">
	<include refid="defaultSql"></include> 
	<where> 
		<if test="ids != null and ids.size() > 0"> 
			<foreach collection="ids" open="id in (" close=")" item="uid" 	  separator=",">
				#{uid}
			</foreach>
		</if>
	</where>
</select>

< foreach >标签用于遍历集合,它的属性:

​ collection:代表要遍历的集合

​ open:代表where子句的开始部分

​ close:代表where子句的结束部分

​ item:代表遍历集合的每个元素,生成的变量名

​ sperator:代表分隔符

(4)测试:

@Test
public void testFindInIds() {
    QueryVo vo = new QueryVo();
    List<Integer> ids = new ArrayList<>();
    ids.add(41);
    ids.add(42);
    ids.add(43);
    ids.add(46);
    ids.add(57);
    vo.setIds(ids);
    List<User> users = userDao.findInIds(vo);
    for(User user : users) {
    	System.out.println(user);
	} 
}

4. < include >标签

​ SQL 中可将重复的 SQL 提取出来,使用时用 < include > 标签引用即可,最终达到 SQL 重用的目的。

(1)定义代码片段:

<!-- 抽取重复的代码片段 --> 
<sql id="defaultSql">
	select * from user
</sql>

(2)引用代码片段:

<!-- 查询所有用户信息 --> 
<select id="findAll" resultType="user"> 
	<include refid="defaultSql"></include>
</select>

<!-- 根据 id 查询用户信息 --> 
<select id="findById" resultType="user" parameterType="int">
	<include refid="defaultSql"></include>
	where id = #{uid}
</select>

三、MyBatis的多表查询

​ 本次案例主要以最为简单的用户和账户的模型来分析 MyBatis 的多表关系。用户为 User 表,账户为Account表。一个用户(User)可以有多个账户(Account)。

注意:

​ 因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。

1. 一对一查询

(0)需求:

​ 查询所有账户信息,关联查询用户信息。

(1)修改 Account 类:

​ 在 Account 类中加入 User 类的对象作为 Account 类的一个属性。

public class Account implements Serializable {
	private Integer id;
    private Integer uid;
    private Double money;
    private User user;
    public User getUser() {
    	return user;
    }
    public void setUser(User user) {
    	this.user = user;
    }
    public Integer getId() {
    	return id; 
    }
    public void setId(Integer id) {
    	this.id = id; 
    }
    public Integer getUid() {
    	return uid; 
    }
    public void setUid(Integer uid) {
    	this.uid = uid; 
    }
    public Double getMoney() {
    	return money; 
    }
    public void setMoney(Double money) {
    	this.money = money; 
    }
    @Override
    public String toString() {
    	return "Account [id=" + id + ", uid=" + uid + ", money=" + money + "]"; 
    } 
}

(2)持久层Dao接口:

public interface IAccountDao {
    /**
    * 查询所有账户,同时获取账户的所属用户名称以及他的地址信息
    * @return
    */
    List<Account> findAll();
}

(3)映射配置文件:

<?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.itheima.dao.IAccountDao">
    
    <!-- 建立对应关系 --> 
    <resultMap type="account" id="accountMap"> 
        <id column="aid" property="id"/>
        <result column="uid" property="uid"/>
        <result column="money" property="money"/>
        <!-- 它是用于指定从表方的引用实体属性的 --> 
        <association property="user" javaType="user"> 
            <id column="id" property="id"/>
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="birthday" property="birthday"/>
            <result column="address" property="address"/>
        </association>
    </resultMap> 
    
    <select id="findAll" resultMap="accountMap">
    	select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
    </select>
</mapper>

(4)测试:

@Test
public void testFindAll() {
	List<Account> accounts = userDao.findAll();
    for(Account au : accounts) {
        System.out.println(au);
        System.out.println(au.getUser());
	} 
}

2. 一对多查询

(0)需求:

​ 查询所有用户信息及用户关联的账户信息。

(1)分析:

​ 用户信息和他的账户信息为一对多关系,并且查询过程中如果用户没有账户信息,此时也要将用户信息查询出来,我们想到了用左外连接查询比较合适。

(2)编写SQL语句:

SELECT
	u.*, acc.id, acc.uid, acc.money
FROM
	user u
LEFT OUTER JOIN account acc ON u.id = acc.uid

(3)在User 类中加入 List< Account >:

public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    private List<Account> accounts;
    public List<Account> getAccounts() {
    	return accounts; 
    }
    public void setAccounts(List<Account> accounts) {
    	this.accounts = accounts; 
    }
    public Integer getId() {
    	return id; 
    }
    public void setId(Integer id) {
    	this.id = id; 
    }
    public String getUsername() {
    	return username; 
    }
    public void setUsername(String username) {
    	this.username = username; 
    }
    public Date getBirthday() {
    	return birthday; 
    }
    public void setBirthday(Date birthday) {
    	this.birthday = birthday; 
    }
    public String getSex() {
    	return sex; 
    }
    public void setSex(String sex) {
    	this.sex = sex; 
    }
    public String getAddress() {
    	return address; 
    }
    public void setAddress(String address) {
    	this.address = address; 
    }
    @Override
    public String toString() {
    	return "User [id=" + id + ", username=" + username + ", birthday=" + birthday+ ", sex=" + sex + ", address="+ address + "]"; 
    } 
}

(4)持久层Dao接口:

/**
* 查询所有用户,同时获取出每个用户下的所有账户信息
* @return
*/
List<User> findAll();

(5)映射配置文件:

<?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.itheima.dao.IUserDao"> 

	<resultMap type="user" id="userMap"> 
        <id column="id" property="id"></id> 
        <result column="username" property="username"/>
        <result column="address" property="address"/>
        <result column="sex" property="sex"/>
        <result column="birthday" property="birthday"/>
        <!-- collection 是用于建立一对多中集合属性的对应关系
             ofType 用于指定集合元素的数据类型
        --> 
        <collection property="accounts" ofType="account"> 
        	<id column="aid" property="id"/>
            <result column="uid" property="uid"/>
            <result column="money" property="money"/>
		</collection>
	</resultMap>
	
	<!-- 配置查询所有操作 --> 
	<select id="findAll" resultMap="userMap">
		select u.*, a.id as aid , a.uid, a.money from user u left outer join account a on u.id = a.uid
	</select>
</mapper>

​ collection部分定义了用户关联的账户信息,表示关联查询结果集。

​ 属性 property 定义了关联查询的结果集存储在 User 对象的上哪个属性。

​ 属性 ofType 定义了关联查询的结果集中的对象类型,即List中的对象类型。

(6)测试:

public class UserTest {
    private InputStream in ;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IUserDao userDao;
	@Test
	public void testFindAll() {
        //6.执行操作
        List<User> users = userDao.findAll();
        for(User user : users) {
            System.out.println("-------每个用户的内容---------");
            System.out.println(user);
            System.out.println(user.getAccounts());
		} 
	}
    @Before//在测试方法执行之前执行
    public void init() throws Exception {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建构建者对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //3.创建 SqlSession 工厂对象
        factory = builder.build(in);
        //4.创建 SqlSession 对象
        session = factory.openSession();
        //5.创建 Dao 的代理对象
        userDao = session.getMapper(IUserDao.class);
    }
    @After//在测试方法执行完成之后执行
    public void destroy() throws Exception{
        session.commit();
        //7.释放资源
        session.close();
        in.close();
	} 
}

四、MyBatis的延迟加载策略

1. 概念

延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.

好处:

​ 先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度快。

坏处:

​ 因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。

2. 需求

​ 查询账户(Account)信息并且关联查询用户(User)信息。先查询账户(Account)信息即可满足要求,当我们需要查询用户(User)信息时再查询用户(User)信息。对用户(User)信息的按需查询就是延迟加载。

​ 在使用MyBatis进行多表查询时,我们通过association、collection 实现一对一及一对多映射。association、collection 具备延迟加载功能。

3. 使用 assocation 实现延迟加载(一对一)

(0)需求:

​ 查询账户信息的同时关联查询用户信息。

(1)账户的持久层Dao接口:

public interface IAccountDao {
    /**
    * 查询所有账户,同时获取账户的所属用户名称以及他的地址信息
    * @return
    */
    List<Account> findAll();
}

(2)账户的持久层映射文件:

<?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.itheima.dao.IAccountDao">
	<!-- 建立对应关系 --> 
	<resultMap type="account" id="accountMap"> 
		<id column="aid" property="id"/>
		<result column="uid" property="uid"/>
		<result column="money" property="money"/>
		<!--
			select: 填写我们要调用的 select 映射的 id 
			column: 填写我们要传递给 select 映射的参数 
		--> 
		<association property="user" javaType="user"
			select="com.itheima.dao.IUserDao.findById"
			column="uid">
		</association>
	</resultMap> 
	
	<select id="findAll" resultMap="accountMap">
		select * from account
	</select>
</mapper>

(4)用户的持久层接口和映射文件:

public interface IUserDao {
    /**
    * 根据 id 查询
    * @param userId
    * @return
    */
    User findById(Integer userId);
}
<?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.itheima.dao.IUserDao">
	
	<!-- 根据 id 查询 --> 
	<select id="findById" resultType="user" parameterType="int" >
		select * from user where id = #{uid}
	</select>
</mapper>

(5)开启 Mybatis 的延迟加载策略:

​ 我们需要在 MyBatis 的配置文件 SqlMapConfig.xml 文件中添加延迟加载的配置。

<!-- 开启延迟加载的支持 -->
<settings> 
	<setting name="lazyLoadingEnabled" value="true"/>
	<setting name="aggressiveLazyLoading" value="false"/>
</settings>

(6)编写测试只查账户信息不查用户信息:

public class AccountTest {
    private InputStream in ;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IAccountDao accountDao;
    @Test
    public void testFindAll() {
        //6.执行操作
        List<Account> accounts = accountDao.findAll();
    }
    @Before//在测试方法执行之前执行
    public void init()throws Exception {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建构建者对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //3.创建 SqlSession 工厂对象
        factory = builder.build(in);
        //4.创建 SqlSession 对象
        session = factory.openSession();
        //5.创建 Dao 的代理对象
        accountDao = session.getMapper(IAccountDao.class);
    }
    @After//在测试方法执行完成之后执行
    public void destroy() throws Exception{
        //7.释放资源
        session.close();
        in.close();
	} 
}

4. 使用 collection 实现延迟加载(一对多)

​ 同样我们也可以在一对多关系配置的< collection >标签中配置延迟加载策略。< collection >结点中也有 select 属性和 column 属性。

(0)需求:

​ 完成加载用户对象时,查询该用户所拥有的账户信息。

(1)在 User 实体类中加入 List< Account >属性:

public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    private List<Account> accounts;
    public List<Account> getAccounts() {
    	return accounts;
    }
    public void setAccounts(List<Account> accounts) {
    	this.accounts = accounts;
    }
    public Integer getId() {
    	return id; 
    }
    public void setId(Integer id) {
    	this.id = id; 
    }
    public String getUsername() {
    	return username; 
    }
    public void setUsername(String username) {
    	this.username = username; 
    }
    public Date getBirthday() {
    	return birthday; 
    }
    public void setBirthday(Date birthday) {
    	this.birthday = birthday; 
    }
    public String getSex() {
    	return sex; 
    }
    public void setSex(String sex) {
    	this.sex = sex; 
    }
    public String getAddress() {
    	return address; 
    }
    public void setAddress(String address) {
    	this.address = address; 
    }
    @Override
    public String toString() {
    	return "User [id=" + id + ", username=" + username + ", birthday=" + birthday
    	+ ", sex=" + sex + ", address="
		+ address + "]"; 
	} 
}

(2)编写用户和账户持久层接口的方法:

/**
* 查询所有用户,同时获取出每个用户下的所有账户信息
* @return
*/
List<User> findAll();

/**
* 根据用户 id 查询账户信息
* @param uid
* @return
*/
List<Account> findByUid(Integer uid);

(3)用户的持久层映射文件:

<resultMap type="user" id="userMap"> 
    <id column="id" property="id"></id> 
    <result column="username" property="username"/>
    <result column="address" property="address"/>
    <result column="sex" property="sex"/>
    <result column="birthday" property="birthday"/>
    <!-- collection 是用于建立一对多中集合属性的对应关系
        ofType 用于指定集合元素的数据类型
        select 是用于指定查询账户的唯一标识(账户的 dao 全限定类名加上方法名称)
        column 是用于指定使用哪个字段的值作为条件查询
	--> 
	<collection property="accounts" ofType="account"
		select="com.itheima.dao.IAccountDao.findByUid"
		column="id">
	</collection>
</resultMap>

<!-- 配置查询所有操作 --> 
<select id="findAll" resultMap="userMap">
	select * from user
</select>

(4)账户的持久层映射文件:

<!-- 根据用户 id 查询账户信息 --> 
<select id="findByUid" resultType="account" parameterType="int">
	select * from account where uid = #{uid}
</select>

(5)测试只加载用户信息:

public class UserTest {
    private InputStream in ;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IUserDao userDao;
    @Test
    public void testFindAll() {
        //6.执行操作
        List<User> users = userDao.findAll();
    }
    @Before//在测试方法执行之前执行
    public void init() throws Exception {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建构建者对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //3.创建 SqlSession 工厂对象
        factory = builder.build(in);
        //4.创建 SqlSession 对象
        session = factory.openSession();
        //5.创建 Dao 的代理对象
        userDao = session.getMapper(IUserDao.class);
    }
    @After//在测试方法执行完成之后执行
    public void destroy() throws Exception{
        session.commit();
        //7.释放资源
        session.close();
        in.close();
    } 
}

五、MyBatis的缓存

​ 像大多数的持久层框架一样,MyBatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。MyBatis 中的缓存分为一级缓存和二级缓存。

1. MyBatis的一级缓存

​ 一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。

​ 第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查询用户信息,得到用户信息,将用户信息存储到一级缓存中。

​ 第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存中获取用户信息。

​ 如果 SqlSession 去执行 commit 操作(执行插入、更新、删除),则清空 SqlSession 中的一级缓存。这样做的目的为了让缓存中存储的都是最新的信息,避免脏读。

2. MyBatis的二级缓存

​ 二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 SQL 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

​ sqlSession1 去查询用户信息,查询到用户信息会将查询数据存储到二级缓存中。

​ sqlSession2 去查询与 sqlSession1 相同的用户信息,首先会去缓存中找是否存在数据,如果存在则直接从缓存中取出数据。

​ 如果 sqlSession3 去执行相同 mapper 映射下的 SQL,执行 commit 提交,将会清空该 mapper 映射下的二级缓存区域的数据。

原文地址:https://www.cnblogs.com/jiajun107/p/13435991.html