title: 2nd level cache collection state is sometimes not synchronized with database
body: <p>We're using <code>EhCache</code> as 2nd level cache (<code>4.3.8.Final</code>) in <code>Hibernate</code> (<code>4.3.8.Final</code>) for Queries (only on read-mostly tables), Entities and Collections between entities.</p>
  
  <p>So you could say that 2nd level cache is used intensively for optimisation purposes.</p>
  
  <p>We never faced any big issues up till now...</p>
  
  <p>Our persistence model concerning the relevant Entities basically looks like below:</p>
  
  <ul>
  <li><p>First we have 2 entities below which have a bi-directional mapping in a natural parent-child relationship: </p>
  
  <pre><code>@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&lt;Child&gt; 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
  }
  </code></pre></li>
  <li><p>Next we have some <code>InvokingEntity</code> which has a one-directional mapping to <code>Parent</code> entity</p>
  
  <pre><code>     @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&lt;Parent&gt; parents = new TreeSet&lt;&gt;();
  
           // getters and setters
       }
  </code></pre></li>
  </ul>
  
  <p>All <code>Entities</code>extend from <code>BaseEntity</code> which contains common properties like <code>id</code> and <code>version</code> for <code>optimistic locking</code> purposes.</p>
  
  <p><br/></p>
  
  <p>So what happens next:</p>
  
  <p>A <code>ChildRepository</code> application all <code>Child</code> entities are deleted and afterwards new ones are created; this happens in the same transaction (<code>trx1</code>):</p>
  
  <p>Extract of delete method:</p>
  
  <pre><code> public void deleteChildsById(List&lt;Long&gt; childIds) {
      if (!childIds.isEmpty()) {
          getSession().createQuery("delete Child as child where child.id in (:childIds)")
                      .setParameterList("childIds", childIds)
                      .setReadOnly(false)
                      .executeUpdate();
      }
  } 
  </code></pre>
  
  <p>Extract of create method:</p>
  
  <pre><code>public void createChilds(List&lt;Child&gt; childs) {
      for (Child child : childs) {
          getSession().save(child);
      }
  }
  </code></pre>
  
  <p>Afterwards, in a 2nd transaction (<code>trx2</code>), the Child entities are retrieved by a natural entity graph traversal:</p>
  
  <pre><code>InvokingEntity invokingEntity = getSession.get(InvokingEntity.class, someId);
  Collection&lt;Child&gt; childs = invokingEntity.getFirstParent().getChilds();
  </code></pre>
  
  <p>Now, the issue is that the <code>childs</code>collection is sometimes empty (in <code>trx2</code>) 
  while we can clearly see multiple <code>Child</code>entities in our database as a result of <code>trx1</code>. </p>
  
  <p>So there clearly is a mismatch between <code>2nd level cache</code> and DB.
  Again, this issue only occurs in roughly 10% of all cases.
  Also not that <code>trx2</code> is always executed 4-5 seconds <strong>AFTER</strong> <code>trx1</code>.</p>
  
  <p>What could cause this situation? A mapping, config or query problem?</p>
  
  <p>There existed an issue in <code>Hibernate</code> where <code>2nd level cache</code> was not invalidated but this seems to be resolved <a href="https://hibernate.atlassian.net/browse/HHH-4910" rel="nofollow">automatic L2 collection cache eviction when an element is added/updated/removed</a> on an earlier version than we're working on.</p>
  
  <p>For completeness, I add an extract of my <code>ehcache</code> config below:</p>
  
  <pre><code>    &lt;defaultCache maxElementsInMemory="10000"
                eternal="false"
                timeToIdleSeconds="1800"
                timeToLiveSeconds="3600"
                overflowToDisk="true"
                diskPersistent="false"
                diskSpoolBufferSizeMB="10"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU"&gt;
      &lt;/defaultCache&gt;
  </code></pre>
  
  <p>Feel free to ask when something is not explained clearly!
  We're open for all suggestions!</p>