L1 Cache in JPA

来源:互联网 发布:投资渠道 知乎 编辑:程序博客网 时间:2024/04/28 17:53

     在对实体做查询的时候经常会涉及到L1 cache, 在JPA 里,L1 cache就是单个Persistence Context内的实体对象缓存,eclipselink实现下有下面几种策略:


public static final int UseDescriptorSetting = -1;public static final int DoNotCheckCache = 0;public static final int CheckCacheByExactPrimaryKey = 1;public static final int CheckCacheByPrimaryKey = 2;public static final int CheckCacheThenDatabase = 3;public static final int CheckCacheOnly = 4;public static final int ConformResultsInUnitOfWork = 5;

     第一个我们先不看,先看下面的:

     1. DoNotCheckCache, 代表的是查询不走一级缓存

     2. CheckCacheByExactPrimaryKey,表示仅按PrimaryKey做查询时,先走L1 cache

     3. CheckCacheByPrimaryKey,表示查询条件里有PrimaryKey的时候,先走L1 cache

     4. CheckCacheThenDatabase, 表示先走L1 cache找匹配的entity,找不到的话再去DB。

     5. CheckCacheOnly, 表示只在cache里面查询。

     6. ConformResultsInUnitOfWork,表示对于查询的结果,会拿L1 Cache里面的缓存实体进行对比,最后返回最新的结果。这个允许我们在不手动flush的前提下,查询出最新的实体对象。(flush是指让缓存中的changeset同步到数据库,可以理解为让数据修改对当前事务可见)

     我们再来看第一个选项:UseDescriptorSetting,这个是ObjectLevelReadQuery的默认值,表示cache的使用取决于你的参数配置,具体的就是在query里面动态的加入Query Hint,比如:

    

   query.setHint(QueryHints.CACHE_USAGE, CacheUsage.CheckCacheOnly);

     对应的Hint值从CacheUsage这个类里面过来(CacheUsage只是把ObjectLevelReadQuery里面这几个属性copy了一遍)。


     所以,对于一个JPA Query,可以通过配置QueryHint来选取对应的缓存策略,如果没有配置对应的hint,默认是DoNotCheckCache。

     但是,如果我们直接使用EntityManager来操纵实体,比如直接调用entityManager.find(Class entityClass, Object pkValue)方法的话,eclipselink的cache选择策略又是不一样的,在EntityManagerImpl下面有这一段代码:

    

 if ((properties == null) || ((!(properties.containsKey("eclipselink.cache-usage"))) && (!(properties.containsKey("javax.persistence.cacheRetrieveMode"))) && (!(properties.containsKey("javax.persistence.cacheStoreMode"))))) {      query.conformResultsInUnitOfWork(); }

      properties就是对应的query hint,在这种情况下,如果property是空或者property里面没有配置对应的cache hint,那么eclipselink默认的会采取最后一种策略,也就是ConformResultsInUnitOfWork,用eclipselink的话来说,在执行查询的时候会先做一个“checkEarlyReturn”,就是对于cacheusage不为0的所有query,先去cache里找,找到了直接return,否则再去DB找。所以当我们用同一主键多次调用find方法的时候最多只会产生一句SQL,比如:

     

    em.find(Employee.class, 2);    em.find(Employee.class, 2);

对应的log如下: