二级缓存问题

二级缓存问题

情形一:

    @Test
    public void testLv2Cache(){
        SqlSession sqlSession=null;
        try {
            sqlSession = MyBatisUtils.openSession();
            Goods goods = sqlSession.selectOne("goods.selectById", 2648);

            Goods goods2 = new Goods();
            goods2.setTitle("测试标题aaaaa");
            goods2.setSubTitle("测试副标题bbbbb");
            goods2.setOriginalCost(200f);
            goods2.setCurrentPrice(400f);
            goods2.setDiscount(0.5f);
            goods2.setIsFreeDelivery(1);
            goods2.setCategoryId(43);
            sqlSession.insert("goods.insertGoods",goods2);

            Goods goods1 = sqlSession.selectOne("goods.selectById", 2648);
            System.out.println(goods.hashCode()+":"+ goods);
            System.out.println(goods1.hashCode()+":"+goods1);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
        System.out.println("-----------------------------------");
        try {
            sqlSession = MyBatisUtils.openSession();
            Goods goods = sqlSession.selectOne("goods.selectById", 2648);
            Goods goods1 = sqlSession.selectOne("goods.selectById", 2648);
            System.out.println(goods.hashCode()+":"+ goods);
            System.out.println(goods1.hashCode()+":"+goods1);

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
        System.out.println("-----------------------------------");
        try {
            sqlSession = MyBatisUtils.openSession();
            Goods goods = sqlSession.selectOne("goods.selectById", 2648);
            Goods goods1 = sqlSession.selectOne("goods.selectById", 2648);
            System.out.println(goods.hashCode()+":"+ goods);
            System.out.println(goods1.hashCode()+":"+goods1);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
    }

情形一的测试结果:

LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.0
JdbcTransaction:143 =>[DEBUG] Opening JDBC Connection
JdbcTransaction:107 =>[DEBUG] Setting autocommit to false on JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
BaseJdbcLogger:135 =>[DEBUG] ==>  Preparing: select * from t_goods where goods_id = ?
BaseJdbcLogger:135 =>[DEBUG] ==> Parameters: 2648(Integer)
BaseJdbcLogger:135 =>[DEBUG] <==      Total: 1
BaseJdbcLogger:135 =>[DEBUG] ==>  Preparing: insert into t_goods(title,sub_title,original_cost,current_price,discount,is_free_delivery,category_id) values(?,?,?,?,?,?,?)
BaseJdbcLogger:135 =>[DEBUG] ==> Parameters: 测试标题aaaaa(String), 测试副标题bbbbb(String), 200.0(Float), 400.0(Float), 0.5(Float), 1(Integer), 43(Integer)
BaseJdbcLogger:135 =>[DEBUG] <==    Updates: 1
BaseJdbcLogger:135 =>[DEBUG] ==>  Preparing: select last_insert_id()
BaseJdbcLogger:135 =>[DEBUG] ==> Parameters: 
BaseJdbcLogger:135 =>[DEBUG] <==      Total: 1
LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.0
BaseJdbcLogger:135 =>[DEBUG] ==>  Preparing: select * from t_goods where goods_id = ?
BaseJdbcLogger:135 =>[DEBUG] ==> Parameters: 2648(Integer)
BaseJdbcLogger:135 =>[DEBUG] <==      Total: 1
680988889:新安怡新生宝宝沐浴露200毫升 SCF981/02
1511574902:新安怡新生宝宝沐浴露200毫升 SCF981/02
JdbcTransaction:86 =>[DEBUG] Rolling back JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
JdbcTransaction:130 =>[DEBUG] Resetting autocommit to true on JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
JdbcTransaction:97 =>[DEBUG] Closing JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
-----------------------------------
LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.0
JdbcTransaction:143 =>[DEBUG] Opening JDBC Connection
JdbcTransaction:107 =>[DEBUG] Setting autocommit to false on JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
BaseJdbcLogger:135 =>[DEBUG] ==>  Preparing: select * from t_goods where goods_id = ?
BaseJdbcLogger:135 =>[DEBUG] ==> Parameters: 2648(Integer)
BaseJdbcLogger:135 =>[DEBUG] <==      Total: 1
LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.0
1077873186:新安怡新生宝宝沐浴露200毫升 SCF981/02
1077873186:新安怡新生宝宝沐浴露200毫升 SCF981/02
JdbcTransaction:130 =>[DEBUG] Resetting autocommit to true on JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
JdbcTransaction:97 =>[DEBUG] Closing JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
-----------------------------------
LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.2
LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.3333333333333333
1077873186:新安怡新生宝宝沐浴露200毫升 SCF981/02
1077873186:新安怡新生宝宝沐浴露200毫升 SCF981/02

情形二:

    @Test
    public void testLv2Cache(){
        SqlSession sqlSession=null;
        try {
            sqlSession = MyBatisUtils.openSession();
            Goods goods = sqlSession.selectOne("goods.selectById", 2648);
            Goods goods1 = sqlSession.selectOne("goods.selectById", 2648);
            System.out.println(goods.hashCode()+":"+ goods.getTitle());
            System.out.println(goods1.hashCode()+":"+goods1.getTitle());
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
        System.out.println("-----------------------------------");
        try {
            sqlSession = MyBatisUtils.openSession();
            Goods goods = sqlSession.selectOne("goods.selectById", 2648);

            Goods goods2 = new Goods();
            goods2.setTitle("测试标题aaaaa");
            goods2.setSubTitle("测试副标题bbbbb");
            goods2.setOriginalCost(200f);
            goods2.setCurrentPrice(400f);
            goods2.setDiscount(0.5f);
            goods2.setIsFreeDelivery(1);
            goods2.setCategoryId(43);
            sqlSession.insert("goods.insertGoods",goods2);
            
            Goods goods1 = sqlSession.selectOne("goods.selectById", 2648);
            System.out.println(goods.hashCode()+":"+ goods.getTitle());
            System.out.println(goods1.hashCode()+":"+goods1.getTitle());
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
        System.out.println("-----------------------------------");
        try {
            sqlSession = MyBatisUtils.openSession();
            Goods goods = sqlSession.selectOne("goods.selectById", 2648);
            Goods goods1 = sqlSession.selectOne("goods.selectById", 2648);
            System.out.println(goods.hashCode()+":"+ goods.getTitle());
            System.out.println(goods1.hashCode()+":"+goods1.getTitle());
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            MyBatisUtils.closeSession(sqlSession);
        }
    }

情形二的测试结果:

DruidDataSource:1002 =>[INFO] {dataSource-1} inited
LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.0
JdbcTransaction:143 =>[DEBUG] Opening JDBC Connection
JdbcTransaction:107 =>[DEBUG] Setting autocommit to false on JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
BaseJdbcLogger:135 =>[DEBUG] ==>  Preparing: select * from t_goods where goods_id = ?
BaseJdbcLogger:135 =>[DEBUG] ==> Parameters: 2648(Integer)
BaseJdbcLogger:135 =>[DEBUG] <==      Total: 1
LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.0
1783966110:新安怡新生宝宝沐浴露200毫升 SCF981/02
1783966110:新安怡新生宝宝沐浴露200毫升 SCF981/02
JdbcTransaction:130 =>[DEBUG] Resetting autocommit to true on JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
JdbcTransaction:97 =>[DEBUG] Closing JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
-----------------------------------
LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.3333333333333333
JdbcTransaction:143 =>[DEBUG] Opening JDBC Connection
JdbcTransaction:107 =>[DEBUG] Setting autocommit to false on JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
BaseJdbcLogger:135 =>[DEBUG] ==>  Preparing: insert into t_goods(title,sub_title,original_cost,current_price,discount,is_free_delivery,category_id) values(?,?,?,?,?,?,?)
BaseJdbcLogger:135 =>[DEBUG] ==> Parameters: 测试标题aaaaa(String), 测试副标题bbbbb(String), 200.0(Float), 400.0(Float), 0.5(Float), 1(Integer), 43(Integer)
BaseJdbcLogger:135 =>[DEBUG] <==    Updates: 1
BaseJdbcLogger:135 =>[DEBUG] ==>  Preparing: select last_insert_id()
BaseJdbcLogger:135 =>[DEBUG] ==> Parameters: 
BaseJdbcLogger:135 =>[DEBUG] <==      Total: 1
LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.5
BaseJdbcLogger:135 =>[DEBUG] ==>  Preparing: select * from t_goods where goods_id = ?
BaseJdbcLogger:135 =>[DEBUG] ==> Parameters: 2648(Integer)
BaseJdbcLogger:135 =>[DEBUG] <==      Total: 1
1783966110:新安怡新生宝宝沐浴露200毫升 SCF981/02
1511574902:新安怡新生宝宝沐浴露200毫升 SCF981/02
JdbcTransaction:86 =>[DEBUG] Rolling back JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
JdbcTransaction:130 =>[DEBUG] Resetting autocommit to true on JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
JdbcTransaction:97 =>[DEBUG] Closing JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@40db2a24]
-----------------------------------
LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.6
LoggingCache:60 =>[DEBUG] Cache Hit Ratio [goods]: 0.6666666666666666
1783966110:新安怡新生宝宝沐浴露200毫升 SCF981/02
1783966110:新安怡新生宝宝沐浴露200毫升 SCF981/02

说明:默认开启了一级缓存,手动开启了二级缓存

相同点:情形1和情形2中都含有三段相同代码

不同点:

情形1在第一段代码查询中间插入了insert()不提交

情形2在第二段代码查询中间插入了insert()不提交

问题

情形1哈希码 —— a b c c c c

680988889    (a)

1511574902  (b)

-------------

1077873186    (c)

1077873186    (c)

-------------

1077873186    (c)

1077873186    (c)


情形2哈希码 —— a a a b a a

1783966110    (a)

1783966110    (a)

--------------

1783966110    (a)

1511574902   (b)

--------------

1783966110    (a)

1783966110    (a)

情形1和情形2无法自圆其说,因为都开启了一级缓存和二级缓存,请解释?谢谢

正在回答

登陆购买课程后可参与讨论,去登陆

1回答

同学你好,1、在MyBatis中,开启了二级缓存并且在代码中插入了一个不提交的insert操作时,这确实会对一级缓存和二级缓存产生干扰,尤其是当这些操作在同一个SqlSession中执行时。

2、下面是对这种情形的详细分析:

    1)一级缓存(SqlSession级别):

        当执行第一次查询时,MyBatis会查询数据库并将结果放入一级缓存。

        接下来,执行了一个insert操作来插入一个新的商品记录(goods2)。由于这个insert操作没有提交(即没有调用sqlSession.commit()),这个变更在数据库中是看不到的,但它会清空一级缓存,因为MyBatis认为数据可能已经发生了改变。

        由于一级缓存已被清空,当您再次执行相同的查询时,MyBatis不会从一级缓存中获取结果,而是会再次查询数据库。

    2)二级缓存(Mapper级别):

        当执行第一次查询时,MyBatis会首先检查二级缓存中是否有结果。如果二级缓存中没有结果,它会查询数据库,并将结果同时放入一级缓存和二级缓存。

        接着,当执行insert操作时,由于这个操作没有提交,它不会影响数据库中的实际数据,但MyBatis会认为数据已经改变,并清空所有相关的一级缓存和二级缓存。这意味着,如果其他SqlSession尝试从二级缓存中获取相同ID的商品,它们将不会看到insert操作的结果,因为缓存已经被清空。

       由于insert操作没有提交,一级缓存和二级缓存都会被清空。这意味再进行查询,MyBatis将不得不重新查询数据库,而不是从缓存中获取结果。

3、在不同的代码中书写增删改操作,都可能会对一级缓存和二级缓存产生干扰,所以出现的结果是不同的。

祝学习愉快!

  • 坨坨儿 提问者 #1

    这解释还是不能自圆其说呀!

    如果情形1是 :      a b    c c   c c 成立的话

    那么情形2应该是:a a    a b   c c,实际却是 a a    a b   a a 


    如果情形2是:       a a    a b    a a 成立的话

    那么情形1应该是:a b    a a    a a,实际却是a b    c c    c c

    2024-04-18 14:34:02
  • 好帮手慕小尤 回复 提问者 坨坨儿 #2

    同学你好,同学将一个try....catch做为一个整体,清除缓存也只是影响当前这个整体,并不影响其他整体。

    1、情况1:第一整体代码中间添加了insert语句,影响了一级与二级缓存所以是没有成功缓存的。当执行第二整体查询SQL,因没有影响所以将数据添加到了缓存中,而第三整体直接就从缓存中读取了。

    2、情况2:在第二整体中添加的insert语句,因第一整体查询已经将查询到的数据添加到缓存中,所以当第二个整体中第一个查询可以直接从缓存中读取。

        当遇到insert语句,从而影响了一级与二级缓存,导致清除了第二个整体的缓存,第二查询需要重新查询了。但第二个整体中的内容,并不会影响第一与三个整体的数据查询。在第三个整体中查看到第一个整体缓存的数据,从而直接从缓存中取数据。 

    祝学习愉快!

    2024-04-18 15:19:33
  • 坨坨儿 提问者 回复 好帮手慕小尤 #3

    所以问题都是出在try...catch块身上,6条sql语句不是一模一样吗?

    回答的挺巧妙的,谢谢了!

    2024-04-18 17:37:40
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
Java工程师 2024版
  • 参与学习       2024    人
  • 提交作业       1318    份
  • 解答问题       1228    个

2024重磅革新,超百小时内容豪华升级,加速提升高级技能与高薪就业竞争力 课程紧贴企业最新人才需求,历经7年持续迭代,帮助万名学子入行转行 从零起点到高阶实战,学习路径稳健顺滑,成就从小白到工程师高薪

了解课程
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师