From 0a809b0fb3c4e02b2a38100d355a5ee52aa20777 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 19 Jan 2018 10:46:49 +1300 Subject: [PATCH] #1239 - When Transaction.setSkipCache(true) ... Query with useQueryCache is still use L2 query cache --- .../server/core/DefaultServer.java | 4 +- .../server/core/OrmQueryRequest.java | 28 +++++----- .../server/core/RelationalQueryRequest.java | 2 +- .../server/query/DefaultOrmQueryEngine.java | 4 +- .../transaction/TestTransactionSkipCache.java | 53 +++++++++++++++++++ 5 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 src/test/java/org/tests/transaction/TestTransactionSkipCache.java diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 8adbf8642..154c847a8 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -1124,6 +1124,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { private SpiOrmQueryRequest createQueryRequest(SpiQuery query, Transaction t) { + if (t == null) { + t = currentServerTransaction(); + } query.setDefaultRawSqlIfRequired(); if (query.isAutoTunable() && !autoTuneService.tuneQuery(query)) { // use deployment FetchType.LAZY/EAGER annotations @@ -1599,7 +1602,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { public List findList(SqlQuery query, Transaction t) { RelationalQueryRequest request = new RelationalQueryRequest(this, relationalQueryEngine, query, t); - try { request.initTransIfRequired(); return request.findList(); diff --git a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java index d6d4376f6..82ab72153 100644 --- a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java @@ -255,19 +255,15 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe public void initTransIfRequired() { // first check if the query requires its own transaction if (transaction == null) { - // maybe a current one - transaction = ebeanServer.currentServerTransaction(); - if (transaction == null) { - if (query.getType().isUpdate()) { - // bulk update or delete query - transaction = ebeanServer.beginServerTransaction(); - } else { - // create an implicit transaction to execute this query - // potentially using read-only DataSource with autoCommit - transaction = ebeanServer.createQueryTransaction(query.getTenantId()); - } - createdTransaction = true; + if (query.getType().isUpdate()) { + // bulk update or delete query + transaction = ebeanServer.beginServerTransaction(); + } else { + // create an implicit transaction to execute this query + // potentially using read-only DataSource with autoCommit + transaction = ebeanServer.createQueryTransaction(query.getTenantId()); } + createdTransaction = true; } persistenceContext = getPersistenceContext(query, transaction); loadContext = new DLoadContext(this, secondaryQueries); @@ -527,8 +523,12 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe query.resetBeanCacheAutoMode(findOne); } + public boolean isQueryCachePut() { + return cacheKey != null && query.getUseQueryCache().isPut(); + } + public boolean isBeanCachePut() { - return query.isBeanCachePut(); + return !transaction.isSkipCache() && query.isBeanCachePut(); } /** @@ -600,7 +600,7 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe @SuppressWarnings("unchecked") public Object getFromQueryCache() { - if (query.getUseQueryCache() == CacheMode.OFF) { + if (query.getUseQueryCache() == CacheMode.OFF || (transaction != null && transaction.isSkipCache())) { return null; } else { cacheKey = query.queryHash(); diff --git a/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java index 75e5cc67f..115c7e93c 100644 --- a/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java @@ -61,7 +61,7 @@ public final class RelationalQueryRequest { /** * Create the BeanFindRequest. */ - public RelationalQueryRequest(SpiEbeanServer server, RelationalQueryEngine engine, SqlQuery q, Transaction t) { + RelationalQueryRequest(SpiEbeanServer server, RelationalQueryEngine engine, SqlQuery q, Transaction t) { this.ebeanServer = server; this.queryEngine = engine; this.query = (SpiSqlQuery) q; diff --git a/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java b/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java index f4764b63f..bed19babe 100644 --- a/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java +++ b/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java @@ -151,7 +151,7 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine { SpiQuery query = request.getQuery(); - if (query.isBeanCachePut()) { + if (request.isBeanCachePut()) { // load the individual beans into the bean cache BeanDescriptor descriptor = request.getBeanDescriptor(); Collection c = result.getActualDetails(); @@ -160,7 +160,7 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine { request.mergeCacheHits(result); - if (query.getUseQueryCache().isPut()) { + if (request.isQueryCachePut()) { // load the query result into the query cache result.setReadOnly(true); request.putToQueryCache(result); diff --git a/src/test/java/org/tests/transaction/TestTransactionSkipCache.java b/src/test/java/org/tests/transaction/TestTransactionSkipCache.java new file mode 100644 index 000000000..d02424c9d --- /dev/null +++ b/src/test/java/org/tests/transaction/TestTransactionSkipCache.java @@ -0,0 +1,53 @@ +package org.tests.transaction; + +import io.ebean.BaseTestCase; +import io.ebean.CacheMode; +import io.ebean.Ebean; +import io.ebean.Transaction; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; +import org.tests.model.basic.Customer; +import org.tests.model.basic.ResetBasicData; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestTransactionSkipCache extends BaseTestCase { + + private void findUseQueryCache() { + + Ebean.find(Customer.class) + .setUseQueryCache(true) + .setBeanCacheMode(CacheMode.PUT) + .where().startsWith("name", "Rob") + .findList(); + } + + private void setup() { + ResetBasicData.reset(); + // load into L2 query cache + findUseQueryCache(); + } + + @Test + public void skipL2QueryCache() { + + setup(); + + Transaction transaction = Ebean.beginTransaction(); + try { + transaction.setSkipCache(true); + + LoggedSqlCollector.start(); + findUseQueryCache(); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql).as("We didn't use the L2 query cache").hasSize(1); + + } finally { + transaction.end(); + } + } + +}