二级缓存收集状态有时与数据库不同步

use*_*927 5 java hibernate jpa ehcache second-level-cache

我们使用EhCache的2级高速缓存(4.3.8.Final中)Hibernate4.3.8.Final)用于查询(仅在主要读取表),实体之间的实体与集合。

所以你可以说二级缓存被大量用于优化目的。

到目前为止,我们从未遇到过任何大问题......

我们关于相关实体的持久性模型基本上如下所示:

  • 首先,我们有 2 个实体,它们在自然父子关系中具有双向映射:

    @Entity
    @Table(...)
    @Cacheable
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    public class Parent extends BaseEntity {
        @Id
        private long id;
    
        @OneToMany(mappedBy="parent", fetch=FetchType.LAZY, cascade = CascadeType.REMOVE)
        @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
        private Set<Child> children;
    
        // getters and setters
    }
    
    @Entity
    @Table(...)
    @Cacheable
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    public class Child extends BaseEntity {
        @Id
        private long id;
    
        @ManyToOne(fetch = FetchType.LAZY, optional = false)
        @JoinColumn(name = "parent_id", nullable = false)
        private Parent parent;
    
        // getters and setters
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 接下来我们有一些InvokingEntity具有到Parent实体的单向映射

         @Entity
         @Table(...)
         @Cacheable
         @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
         public class InvokingEntity extends BaseEntity {
             @Id
             private long id;
    
             @Fetch(FetchMode.SUBSELECT)
             @OneToMany(fetch = FetchType.LAZY, mappedBy = "invokingEntity", cascade = CascadeType.ALL, orphanRemoval = true)
             @OrderBy("sequence asc")
             @SortComparator(ParentBySequenceComparator.class)
             @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
             private Set<Parent> parents = new TreeSet<>();
    
             // getters and setters
         }
    
    Run Code Online (Sandbox Code Playgroud)

所有Entities扩展BaseEntity都包含通用属性,例如idversion用于optimistic locking目的。


那么接下来会发生什么:

一个ChildRepository应用程序的所有Child实体都将被删除,之后新的创建; 这发生在同一个事务 ( trx1) 中:

删除方法的摘录:

 public void deleteChildsById(List<Long> childIds) {
    if (!childIds.isEmpty()) {
        getSession().createQuery("delete Child as child where child.id in (:childIds)")
                    .setParameterList("childIds", childIds)
                    .setReadOnly(false)
                    .executeUpdate();
    }
} 
Run Code Online (Sandbox Code Playgroud)

创建方法的摘录:

public void createChilds(List<Child> childs) {
    for (Child child : childs) {
        getSession().save(child);
    }
}
Run Code Online (Sandbox Code Playgroud)

之后,在第二个事务 ( trx2) 中,通过自然实体图遍历检索子实体:

InvokingEntity invokingEntity = getSession.get(InvokingEntity.class, someId);
Collection<Child> childs = invokingEntity.getFirstParent().getChilds();
Run Code Online (Sandbox Code Playgroud)

现在,问题是childs集合有时是空的(在 中trx2),而Child由于trx1.

所以显然2nd level cache和 DB之间存在不匹配。同样,此问题仅发生在所有情况的大约 10% 中。也不trx2是总是在 4-5 秒 执行trx1

什么可能导致这种情况?映射、配置或查询问题?

Hibernatewhere is2nd level cache not invalidated存在一个问题,但是在比我们正在处理的早期版本上添加/更新/删除元素时,这似乎可以解决自动 L2 集合缓存逐出问题。

为了完整起见,我ehcache在下面添加了我的配置的摘录:

    <defaultCache maxElementsInMemory="10000"
              eternal="false"
              timeToIdleSeconds="1800"
              timeToLiveSeconds="3600"
              overflowToDisk="true"
              diskPersistent="false"
              diskSpoolBufferSizeMB="10"
              diskExpiryThreadIntervalSeconds="120"
              memoryStoreEvictionPolicy="LRU">
    </defaultCache>
Run Code Online (Sandbox Code Playgroud)

有什么不明白的地方随时问!我们对所有建议持开放态度!