Mybatis的缓存(实例)

本文介绍了Mybatis的缓存机制,包括一级缓存的概念、工作原理和清空时机,以及二级缓存的配置和使用步骤。通过实例展示了在不同操作后缓存的行为,强调了在使用缓存时需要注意的数据一致性问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

----->项目源码

概念

  • 缓存:存于内存中的临时数据
  • 使用缓存优点:减少和数据库的交互次数,提高执行效率。
  • 缓存适用于:经常查询并且不经常改变的、正确与否对最终结果影响不大的数据。
  • 缓存不适用于: 经常改变的、正确与否对最终结果影响很大的。如:商品的库存,银行的汇率,股市的价格。

实例

Mybatis中的一级缓存

Mybatis中的 一级缓存,指的是 SqlSession对象的缓存。

当我们执行查询之后,查询的结果会同时存入SqlSession为我们提供一块区域中,该区域的结构是一个Map。

当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有此数据,有则直接取用。

当SqlSession对象消失时,mybatis的一级缓存也就消失了。

本例的目录结构:
在这里插入图片描述
mysql中的user表:
在这里插入图片描述
UserTest.java:

/**
 * User测试类
 */
public class UserTest {
    private InputStream in;
    private  SqlSessionFactory factory;
    private SqlSession sqlSession;
    private IUserDao userDao;

    @Before//用于在测试方法执行之前执行
    public void init()throws Exception{
        //1.读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取SqlSessionFactory
        factory = new SqlSessionFactoryBuilder().build(in);
        //3.获取SqlSession对象
        sqlSession = factory.openSession(true);
        //4.获取dao的代理对象
        userDao = sqlSession.getMapper(IUserDao.class);
    }

    @After//用于在测试方法执行之后执行
    public void destroy()throws Exception{
        //提交事务
        // sqlSession.commit();
        //6.释放资源
        sqlSession.close();
        in.close();
    }

    /**
     * 测试一级缓存
     */
    @Test
    public void testFirstLevelCache(){
        User user1 = userDao.findById(6);
        System.out.println(user1);
       
        User user2 = userDao.findById(6);
        System.out.println(user2);

        System.out.println(user1 == user2);
    }

执行testFirstLevelCache()方法,测试结果如下:
在这里插入图片描述
可见两次查询的结果是同一个对象,说明使用了缓存。

在测试代码中查询后,关闭sqlSession并再次获取,之后再查询一次:

    /**
     * 测试一级缓存
     */
    @Test
    public void testFirstLevelCache(){
        User user1 = userDao.findById(6);
        System.out.println(user1);
        sqlSession.close();
        
        // 再次获取SqlSession对象
        sqlSession = factory.openSession();
		userDao = sqlSession.getMapper(IUserDao.class);

        User user2 = userDao.findById(6);
        System.out.println(user2);

        System.out.println(user1 == user2);
    }

在这里插入图片描述
测试结果表明两次查询获取的对象不是同一个,且获取了两次SqlSession对象,说明SqlSession对象消失时,mybatis的一级缓存也就消失了,毕竟这种缓存是依赖于SqlSession对象的。

此外,SqlSession对象的clearCache()方法也可以清除缓存。

清空一级缓存的时机

一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除, commit(), close()等方法时,就会清空一级缓存。这样做的目的是,为了让缓存中存储的是最新的信息,避免脏读。

例如,IUserDAO中添加更新记录的方法:

    /**
     * 更新用户信息
     * @param user
     */
    void updateUser(User user);

并配置映射(IUserDAO.xml):

    <!-- 更新用户信息-->
    <update id="updateUser" parameterType="user">
        update user set username=#{username},address=#{address} where id=#{id}
    </update>

添加测试方法:

    /**
     * 测试缓存的同步
     */
    @Test
    public void testClearlCache(){
        //1.根据id查询用户
        User user1 = userDao.findById(6);
        System.out.println(user1);

        //2.更新用户信息
        user1.setUsername("男林志玲");
        user1.setAddress("香港");
        userDao.updateUser(user1);

        //3.再次查询id为6的用户
        User user2 = userDao.findById(6);
        System.out.println(user2);

        System.out.println(user1 == user2);
    }

测试结果:
在这里插入图片描述
可以看到,SqlSession执行了update后,当需要查询用户时并没有从缓存中取,而是又进行了一次查询,因为update后缓存已经被清空了。

Mybatis中的二级缓存

Mybatis中的二级缓存指的是 SqlSessionFactory对象的缓存——由同一个SqlSessionFactory对象创建的SqlSession共享其缓存
在这里插入图片描述
二级缓存的使用步骤:

  1. 让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置setting的cacheEnabled属性)
  2. 让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
  3. 让当前的statement支持二级缓存(在select标签中配置)

下面按部就班进行二级缓存的配置——

  1. SqlMapConfig.xml:
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置,为 true 代表开启二级缓存;为
false 代表不开启二级缓存。

  1. IUserDao.xml:
<mapper namespace="com.zhu.dao.IUserDao">
    <!--开启user支持二级缓存-->
    <cache/>
    
	......
	
</mapper>

<cache>标签表示当前这个 mapper 映射将使用二级缓存。

  1. IUserDao.xml 的 statement 上面的 useCache属性:
    <!-- 根据id查询用户 -->
    <select id="findById" parameterType="INT" resultType="user" useCache="true">
        select * from user where id = #{uid}
    </select>

准备就绪,新建一个测试类:

public class SecondLevelCacheTest {

    private InputStream in;
    private SqlSessionFactory factory;

    @Before//用于在测试方法执行之前执行
    public void init()throws Exception{
        //1.读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取SqlSessionFactory
        factory = new SqlSessionFactoryBuilder().build(in);

    }

    @After//用于在测试方法执行之后执行
    public void destroy()throws Exception{
        in.close();
    }

    /**
     * 测试一级缓存
     */
    @Test
    public void testFirstLevelCache(){
        SqlSession sqlSession1 = factory.openSession();
        IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);
        User user1 = dao1.findById(6);
        System.out.println(user1);
        // 一级缓存消失
        sqlSession1.close();

        SqlSession sqlSession2 = factory.openSession();
        IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);
        User user2 = dao2.findById(6);
        System.out.println(user2);
        sqlSession2.close();

        System.out.println(user1 == user2);
    }


}

测试结果:
在这里插入图片描述
从结果中可以看到,虽然有两个不同的sqlSession执行查询,但是stament只执行了一次,说明sqlSession2的查询使用的是缓存中的数据。此外,两次查询的结果对象依然是不同的,说明二级缓存的是数据而不是对象,当查询语句一致时,将从缓存中把数据填充到新的对象中。

当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这样就可以使用序列化
方式来保存对象

总结

  • Mybatis中的 一级缓存,指的是 SqlSession对象 的缓存
  • Mybatis中的二级缓存,指的是 SqlSessionFactory对象的缓存,且需要在配置中开启缓存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值