MyBatis的缓存机制:一级缓存(SqlSession级别)

在实际项目开发中,通常对数据库查询的性能要求很高,而MyBatis提供了查询缓存来缓存数据,从而达到提高查询性能的要求.MyBatis的查询缓存分为一级缓存和二级缓存.一级缓存是SqlSession级别的缓存,二级缓存是mapper级别的缓存,二级缓存是多个SqlSession共享的.MyBatis通过缓存机制减轻数据压力,提高数据库性能.
MyBatis的一级缓存是SqlSession级别的缓存,在操作数据库时需要构造SqlSession对象,当在同一个SqlSession中执行两次相同的sql语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率,需要注意的是,如果SqlSession执行了DML操作(insert,update,delete)并提交到数据库,MyBatis则会清空SqlSession中的一级缓存,这样做的目的是为了保证缓存中存储的是最新效率,避免出现脏读现象.
当一个SqlSession结束后该SqlSession中的一级缓存也就不存在了.MyBatis默认开启一级缓存,不需要进行任何配置.
示例:OneLevelCacheTest
1.userMapper.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">
<mapper namespace="org.fkit.mapper.UserMapper">
    <!-- 根据ID查询 -->
    <select id="selectUserById" parameterType="int" resultMap="userResultMap">
        SELECT * FROM tb_user WHERE ID=#{id}
    </select>
    <!-- 查询所有User -->
    <select id="selectAllUser" resultMap="userResultMap">
        SELECT * FROM tb_user
    </select>
    <!-- 根据ID删除User -->
    <delete id="deleteUserById" parameterType="int">
        DELETE FROM tb_user WHERE id=#{id}
    </delete>
    <!-- 映射user对象的resultMap -->
    <resultMap type="org.fkit.domain.User" id="userResultMap">
        <id property="id" column="ID" />
        <result property="username" column="USERNAME" />
        <result property="loginname" column="LOGINNAME" />
        <result property="password" column="PASSWORD" />
        <result property="phone" column="PHONE" />
        <result property="address" column="ADDRESS" />
    </resultMap>
</mapper>
2..userMapper.java
public interface UserMapper
{
    //根据ID查询User
    User selectUserById(Integer id);
    //查询所有User
    List<User> selectAllUser();
    //根据ID删除User
    void deleteUserById(Integer id);
}
3.控制器
    @GetMapping("/mysql/cache/")
    public void cache()
    {
        //获得SqlSession实例
        SqlSession sqlSession = FKSqlSessionFactory.getSqlSession();
        //获得Mapper接口代理对象
        UserMapper em = sqlSession.getMapper(UserMapper.class);
        //按ID查询
        User user1 = em.selectUserById(5);
        User user2 = em.selectUserById(6);
        User user3 = em.selectUserById(5);
        
    }
4.输出
可以看出第一次查询ID=5的User对象时执行了一条select语句,但是第二次获取id为5的User对象时,并没有执行select语句.因为此时一级缓存也就是SqlSession缓存已经缓存了id=5的User对象,MyBatis直接从缓存中将对象取出来,并没有再次去数据库查询,所以第二次没有再执行select语句.
5.控制器
    @GetMapping("/mysql/cache2/")
    public void cache2()
    {
        //获得SqlSession实例
        SqlSession sqlSession = FKSqlSessionFactory.getSqlSession();
        //获得Mapper接口代理对象
        UserMapper em = sqlSession.getMapper(UserMapper.class);
        //按ID查询
        User user1 = em.selectUserById(5);
        em.deleteUserById(5);
        User user2 = em.selectUserById(5);
    }
6.输出
在第一次查询id为5的User对象之后,执行了一个delete操作,MyBatis为了保证缓存中的是最新的信息,会清空SqlSession中的缓存,当第二次获取id为5的User对象时,一级缓存也就是SqlSession缓存中并没有缓存任何对象,所以MyBatis再次执行select语句去查询id=5的对象
由于我们没有执行
sqlSession.commit();
所以数据库仍然存在ID=5的User对象