diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java index 508bb04de..6c8780a2a 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java @@ -80,7 +80,8 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager private String _schedule = null; protected Set _includedTypes = new HashSet(); protected Set _excludedTypes = new HashSet(); - + protected boolean _evictOnBulkUpdate = true; + public String getName() { return _name; } @@ -541,4 +542,12 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager public DataCache selectCache(OpenJPAStateManager sm) { return this; } + + public boolean getEvictOnBulkUpdate(){ + return _evictOnBulkUpdate; + } + + public void setEvictOnBulkUpdate(boolean b){ + _evictOnBulkUpdate = b; + } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCache.java b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCache.java index f9fc48db8..7ceaf8dd2 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCache.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCache.java @@ -304,4 +304,9 @@ public interface DataCache * Returns number of read/write request and cache hit ratio data. */ public CacheStatistics getStatistics(); + + /** + * Returns whether the the cache needs to be updated when bulk updates as executed. Defaults to true. + */ + public boolean getEvictOnBulkUpdate(); } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java index 4980e629e..6d8aa2369 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java @@ -117,7 +117,7 @@ public class DataCacheStoreManager DataCache cache; for (Class cls : classes) { cache = mdr.getMetaData(cls, loader, false).getDataCache(); - if (cache != null) + if (cache != null && cache.getEvictOnBulkUpdate()) cache.removeAll(cls, false); } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java index 8b65c16e8..0c5009424 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java @@ -381,4 +381,14 @@ public class DelegatingDataCache throw translate(re); } } + + public boolean getEvictOnBulkUpdate() { + if (_cache == null) + return false; + try { + return _cache.getEvictOnBulkUpdate(); + } catch (RuntimeException re) { + throw translate(re); + } + } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java index 246bdab0b..64407a90f 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java @@ -380,7 +380,7 @@ public class QueryCacheStoreQuery // evict from the data cache for (int i = 0; i < cmd.length; i++) { - if (cmd[i].getDataCache() != null) + if (cmd[i].getDataCache() != null && cmd[i].getDataCache().getEvictOnBulkUpdate()) cmd[i].getDataCache().removeAll( cmd[i].getDescribedType(), true); } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java index 0ca64e3cf..2638fd52a 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java @@ -131,7 +131,7 @@ public abstract class AbstractStoreQuery } finally { for (ClassMetaData cmd : getAccessPathMetaDatas(q)) { DataCache cache = cmd.getDataCache(); - if (cache != null) { + if (cache != null && cache.getEvictOnBulkUpdate()) { cache.removeAll(cmd.getDescribedType(), true); } } @@ -144,7 +144,7 @@ public abstract class AbstractStoreQuery } finally { for (ClassMetaData cmd : getAccessPathMetaDatas(q)) { DataCache cache = cmd.getDataCache(); - if (cache != null) { + if (cache != null && cache.getEvictOnBulkUpdate()) { cache.removeAll(cmd.getDescribedType(), true); } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java index 3ce68c31d..3f990dcd7 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java @@ -793,7 +793,7 @@ public class ExpressionStoreQuery } finally { for (ClassMetaData cmd : getAccessPathMetaDatas(q)) { DataCache cache = cmd.getDataCache(); - if (cache != null) { + if (cache != null && cache.getEvictOnBulkUpdate()) { cache.removeAll(cmd.getDescribedType(), true); } } @@ -810,7 +810,7 @@ public class ExpressionStoreQuery } finally { for (ClassMetaData cmd : getAccessPathMetaDatas(q)) { DataCache cache = cmd.getDataCache(); - if (cache != null) { + if (cache != null && cache.getEvictOnBulkUpdate()) { cache.removeAll(cmd.getDescribedType(), true); } } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkUpdatesDataCacheEviction.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkUpdatesDataCacheEviction.java index 6fd88d291..6cb99a29e 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkUpdatesDataCacheEviction.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkUpdatesDataCacheEviction.java @@ -21,10 +21,14 @@ package org.apache.openjpa.persistence.datacache; import javax.persistence.Cache; import javax.persistence.EntityManager; +import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI; +import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI; import org.apache.openjpa.persistence.test.SingleEMFTestCase; public class TestBulkUpdatesDataCacheEviction extends SingleEMFTestCase { Object[] props = new Object[] { CLEAR_TABLES, CachedEntityStatistics.class, "openjpa.DataCache", "true" }; + Object[] noEvictProps = new Object[] { CLEAR_TABLES, CachedEntityStatistics.class + , "openjpa.DataCache", "true(EvictOnBulkUpdate=false)" }; public void setUp() throws Exception { super.setUp(props); @@ -85,7 +89,58 @@ public class TestBulkUpdatesDataCacheEviction extends SingleEMFTestCase { em.close(); } } + + public void testUpdateNoEvict(){ + OpenJPAEntityManagerFactorySPI emf = createNamedEMF(getPersistenceUnitName(), noEvictProps); + Cache cache = emf.getCache(); + OpenJPAEntityManagerSPI em = emf.createEntityManager(); + try { + CachedEntityStatistics e = createEntity(em); + assertTrue(cache.contains(CachedEntityStatistics.class, e.getId())); + em.clear(); + String update = "UPDATE CachedEntityStatistics s SET s.firstName = :name WHERE s.id = :id"; + String name = "name_" + System.currentTimeMillis(); + // execute update, this should result in a cache eviction + em.getTransaction().begin(); + assertEquals(1, em.createQuery(update).setParameter("name", name).setParameter("id", e.getId()) + .executeUpdate()); + em.getTransaction().commit(); + assertTrue(cache.contains(CachedEntityStatistics.class, e.getId())); + + CachedEntityStatistics postUpdate = em.find(CachedEntityStatistics.class, e.getId()); + assertNotEquals(name, postUpdate.getFirstName()); + }finally{ + emf.close(); + } + } + + public void testDeleteNoEvict() throws Exception { + OpenJPAEntityManagerFactorySPI emf = createNamedEMF(getPersistenceUnitName(), noEvictProps); + Cache cache = emf.getCache(); + OpenJPAEntityManagerSPI em = emf.createEntityManager(); + try { + CachedEntityStatistics e = createEntity(em); + assertTrue(cache.contains(CachedEntityStatistics.class, e.getId())); + em.clear(); + + String delete = "DELETE FROM CachedEntityStatistics s WHERE s.id = :id"; + // execute update, this should NOT result in a cache eviction + em.getTransaction().begin(); + assertEquals(1, em.createQuery(delete).setParameter("id", e.getId()).executeUpdate()); + em.getTransaction().commit(); + assertTrue(cache.contains(CachedEntityStatistics.class, e.getId())); + + em.clear(); + + CachedEntityStatistics postUpdate = em.find(CachedEntityStatistics.class, e.getId()); + assertNotNull(postUpdate); + + } finally { + em.close(); + } + } + private CachedEntityStatistics createEntity(EntityManager em) { em.getTransaction().begin(); CachedEntityStatistics e = new CachedEntityStatistics(); diff --git a/openjpa-project/src/doc/manual/ref_guide_caching.xml b/openjpa-project/src/doc/manual/ref_guide_caching.xml index 497316efa..702d75347 100644 --- a/openjpa-project/src/doc/manual/ref_guide_caching.xml +++ b/openjpa-project/src/doc/manual/ref_guide_caching.xml @@ -345,6 +345,18 @@ to evict values from the cache every 120 minutes. true(EvictionSchedule='+120') + + + Bulk updates and cache eviction + + +For the example, setting EvictOnBulkUpdate to false will tell OpenJPA to not evict from the DataCache when executing +and UPDATE or DELETE statement. The default for the value is true. + + +<property name="openjpa.DataCache" value="true(EvictOnBulkUpdate=false)"/> + +
Distributing instances across cache partitions @@ -371,7 +383,7 @@ as follows: <property name="openjpa.DataCache" value="partitioned(PartitionType=concurrent,partitions= '(name=a,cacheSize=100),(name=b,cacheSize=200)')"/> - +
The distribution policy is configured by a full-qualified class name that implements