日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

MyBatis的一級(同SqlSession會話),二級(不同SqlSession會話)緩存使用

作者:小徐敲java 更新時間: 2024-04-06 編程語言

1:一級緩存要生效,必須滿足以下條件條件

  • 必須是相同的會話
  • 必須是同一個 mapper,即同一個 namespace
  • 必須是相同的 statement,即同一個 mapper 中的同一個方法
  • 必須是相同的 SQL 和參數(shù)
  • 查詢語句中間沒有執(zhí)行 session.clearCache() 方法
  • 查詢語句中間沒有執(zhí)行 insert/update/delete 方法

2:與 SpringBoot 集成時一級緩存不生效原因

  • 因為一級緩存是會話級別的,要生效的話,必須要在同一個 SqlSession 中。但是與 SpringBoot 集成的 MyBatis,默認(rèn)每次執(zhí)行 SQL 語句時,都會創(chuàng)建一個新的 SqlSession!所以一級緩存才沒有生效。
  • 當(dāng)調(diào)用 mapper 的方法時,最終會執(zhí)行到 SqlSessionUtils 的 getSqlSession 方法,在這個方法中會嘗試在事務(wù)管理器中獲取 SqlSession,如果沒有開啟事務(wù),那么就會 new 一個 DefaultSqlSession。所以說,即便在同一個方法中,通過同一個 mapper 連續(xù)調(diào)用兩次相同的查詢方法,也不會觸發(fā)一級緩存

3:解決與 SpringBoot 集成時一級緩存不生效問題

只要將方法加上 @Transactional 注解開啟事務(wù),那么一級緩存就會生效

4:mybatis為什么要有二級緩存

  • 業(yè)務(wù)系統(tǒng)中存在很多的靜態(tài)數(shù)據(jù)如,字典表、菜單表、權(quán)限表等,這些數(shù)據(jù)的特性是不會輕易修改但又是查詢的熱點數(shù)據(jù)
  • 一級緩存針對的是同一個會話當(dāng)中相同 SQL,并不適合熱點數(shù)據(jù)的緩存場景
  • 為了解決這個問題引入了二級緩存,它脫離于會話之外,多個會話可以使用相同的緩存

5:配置啟動mybatis有二級緩存

  • 二級緩存需要手動來開啟,MyBatis 默認(rèn)沒有開啟二級緩存
  • 在 yaml 中配置 cache-enabled 為 true
mybatis-plus:
  configuration:
    cache-enabled: true
  • 實體類實現(xiàn) Serializable 接口和生成SerialVersionUID
public class SysNotification implements Serializable {
	private static final long serialVersionUID = 3470806756562029897L;
  • 測試當(dāng)發(fā)送兩次 get 請求時(兩個不同的會話),通過日志可以發(fā)現(xiàn)第二次查詢使用的是緩存
Cache Hit Ratio [org.jeecg.modules.system.mapper.SysNotificationMapper]: 0.5

生效的條件:

  • 當(dāng)會話提交或關(guān)閉之后才會填充二級緩存
  • 必須是同一個 mapper,即同一個命名空間
  • 必須是相同的 statement,即同一個 mapper 中的同一個方法
  • 必須是相同的 SQL 語句和參數(shù)
  • 如果 readWrite=true(默認(rèn)就是true),實體對像必須實現(xiàn) Serializable 接口

失效的條件:

  • 只有修改會話提交之后,才會執(zhí)行清空操作
  • 任何一種增刪改操作都會清空整個 namespace 中的緩存

6:為什么 MyBatis 默認(rèn)不開啟二級緩存?

  • 二級緩存雖然能帶來一定的好處,但是有很大的隱藏危害!
  • 它的緩存是以 namespace(mapper) 為單位的,不同 namespace 下的操作互不影響。且 insert/update/delete 操作會清空所在 namespace 下的全部緩存
  • 假設(shè)現(xiàn)在有 ItemMapper 以及 XxxMapper,在 XxxMapper 中做了表關(guān)聯(lián)查詢,且做了二級緩存。此時在 ItemMapper 中將 item 信息給刪了,由于不同 namespace 下的操作互不影響,XxxMapper 的二級緩存不會變,那之后再次通過 XxxMapper 查詢的數(shù)據(jù)就不對了,非常危險,來看一個例子:

@Mapper
@Repository
@CacheNamespace
public interface XxxMapper {

    @Select("select i.id itemId,i.name itemName,p.amount,p.unit_price unitPrice " +
            "from item i JOIN payment p on i.id = p.item_id where i.id = #{id}")
    List<PaymentVO> getPaymentVO(Long id);

}


@Autowired
private XxxMapper xxxMapper;

@Test
void test() {
  System.out.println("==================== 查詢PaymentVO ====================");
  List<PaymentVO> voList = xxxMapper.getPaymentVO(1L);
  System.out.println(JSON.toJSONString(voList.get(0)));
  System.out.println("====================  更新item表的name ==================== ");
  Item item = itemMapper.selectById(1);
  item.setName("java并發(fā)編程");
  itemMapper.updateById(item);
  System.out.println("====================  重新查詢PaymentVO ==================== ");
  List<PaymentVO> voList2 = xxxMapper.getPaymentVO(1L);
  System.out.println(JSON.toJSONString(voList2.get(0)));
}
  • 上面的代碼,test() 方法中前后兩次調(diào)用了 xxxMapper.getPaymentVO 方法,因為沒有加 @Transactional 注解,所以前后兩次查詢,是兩個不同的會話,第一次查詢完后,SqlSession 會自動 commit,所以二級緩存能夠生效;
  • 然后在中間進(jìn)行了 Item 表的更新操作,修改了下名稱;
  • 由于 itemMapper 與 xxxMapper 不是同一個命名空間,所以 itemMapper 執(zhí)行的更新操作不會影響到 xxxMapper 的二級緩存;
    再次調(diào)用 xxxMapper.getPaymentVO,發(fā)現(xiàn)取出的值是走緩存的,itemName 還是老的。但實際上 itemName 在上面已經(jīng)被改了!
  • 所以說,二級緩存的隱藏危害是比較大的,當(dāng)有表關(guān)聯(lián)時,一個不注意就會出問題,不建議使用

7:可以使用Spring緩存注解@Cacheable、@CacheEvict、@CachePut

原文鏈接:https://blog.csdn.net/qq_19891197/article/details/131460812

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新