Repository: cayenne Updated Branches: refs/heads/master 3d2b091b6 -> 4f4ade0ee
CAY-2186 Always run MySQL PK generator in separate transaction Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/4f4ade0e Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/4f4ade0e Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/4f4ade0e Branch: refs/heads/master Commit: 4f4ade0eead7ddafc59b21343d33abc5ffa5ae5a Parents: 3d2b091 Author: Nikita Timofeev <stari...@gmail.com> Authored: Mon Feb 20 11:43:17 2017 +0300 Committer: Nikita Timofeev <stari...@gmail.com> Committed: Mon Feb 20 11:43:17 2017 +0300 ---------------------------------------------------------------------- .../cayenne/dba/mysql/MySQLPkGenerator.java | 20 +++++++++++- .../apache/cayenne/tx/CayenneTransaction.java | 5 +++ .../apache/cayenne/tx/ExternalTransaction.java | 5 +++ .../java/org/apache/cayenne/tx/Transaction.java | 5 +++ .../configuration/server/ServerRuntimeIT.java | 32 ++++++++++++++++++++ .../apache/cayenne/tx/UserTransactionIT.java | 5 +++ 6 files changed, 71 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/4f4ade0e/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLPkGenerator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLPkGenerator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLPkGenerator.java index 9e30749..9812f5f 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLPkGenerator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLPkGenerator.java @@ -29,11 +29,17 @@ import org.apache.cayenne.access.DataNode; import org.apache.cayenne.dba.JdbcAdapter; import org.apache.cayenne.dba.JdbcPkGenerator; import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.tx.BaseTransaction; +import org.apache.cayenne.tx.Transaction; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** */ public class MySQLPkGenerator extends JdbcPkGenerator { + private static final Log logger = LogFactory.getLog(MySQLPkGenerator.class); + MySQLPkGenerator(JdbcAdapter adapter) { super(adapter); } @@ -55,6 +61,15 @@ public class MySQLPkGenerator extends JdbcPkGenerator { SQLException exception = null; long pk = -1L; + // Start new transaction if needed, can any way lead to problems when + // using external transaction manager. We can only warn about it. + // See https://issues.apache.org/jira/browse/CAY-2186 for details. + Transaction transaction = BaseTransaction.getThreadTransaction(); + if(transaction != null && transaction.isExternal()) { + logger.warn("Using MysqlPkGenerator with external transaction manager may lead to inconsistent state."); + } + BaseTransaction.bindThreadTransaction(null); + try (Connection con = node.getDataSource().getConnection()) { if (con.getAutoCommit()) { @@ -86,6 +101,8 @@ public class MySQLPkGenerator extends JdbcPkGenerator { } } catch (SQLException otherEx) { exception = processSQLException(otherEx, null); + } finally { + BaseTransaction.bindThreadTransaction(transaction); } // check errors @@ -118,7 +135,8 @@ public class MySQLPkGenerator extends JdbcPkGenerator { @Override protected String pkTableCreateString() { return "CREATE TABLE IF NOT EXISTS AUTO_PK_SUPPORT " + - "(TABLE_NAME CHAR(100) NOT NULL, NEXT_ID BIGINT NOT NULL, UNIQUE (TABLE_NAME))"; + "(TABLE_NAME CHAR(100) NOT NULL, NEXT_ID BIGINT NOT NULL, UNIQUE (TABLE_NAME)) " + + "ENGINE=" + MySQLAdapter.DEFAULT_STORAGE_ENGINE; } /** http://git-wip-us.apache.org/repos/asf/cayenne/blob/4f4ade0e/cayenne-server/src/main/java/org/apache/cayenne/tx/CayenneTransaction.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/tx/CayenneTransaction.java b/cayenne-server/src/main/java/org/apache/cayenne/tx/CayenneTransaction.java index dba12d9..5554f07 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/tx/CayenneTransaction.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/tx/CayenneTransaction.java @@ -131,4 +131,9 @@ public class CayenneTransaction extends BaseTransaction { throw new CayenneRuntimeException(deferredException); } } + + @Override + public boolean isExternal() { + return false; + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/4f4ade0e/cayenne-server/src/main/java/org/apache/cayenne/tx/ExternalTransaction.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/tx/ExternalTransaction.java b/cayenne-server/src/main/java/org/apache/cayenne/tx/ExternalTransaction.java index 8fd4316..8afa94f 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/tx/ExternalTransaction.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/tx/ExternalTransaction.java @@ -43,4 +43,9 @@ public class ExternalTransaction extends BaseTransaction { protected void processRollback() { logger.logRollbackTransaction("no rollback - transaction controlled externally."); } + + @Override + public boolean isExternal() { + return true; + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/4f4ade0e/cayenne-server/src/main/java/org/apache/cayenne/tx/Transaction.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/tx/Transaction.java b/cayenne-server/src/main/java/org/apache/cayenne/tx/Transaction.java index f87e8c3..0f03007 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/tx/Transaction.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/tx/Transaction.java @@ -63,4 +63,9 @@ public interface Transaction { Map<String, Connection> getConnections(); void addListener(TransactionListener listener); + + /** + * Is this transaction managed by external transaction manager + */ + boolean isExternal(); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/4f4ade0e/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeIT.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeIT.java b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeIT.java index 4668264..30b5e63 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeIT.java @@ -18,8 +18,10 @@ ****************************************************************/ package org.apache.cayenne.configuration.server; +import org.apache.cayenne.ObjectContext; import org.apache.cayenne.PersistenceState; import org.apache.cayenne.di.Inject; +import org.apache.cayenne.query.ObjectSelect; import org.apache.cayenne.testdo.testmap.Artist; import org.apache.cayenne.tx.Transaction; import org.apache.cayenne.tx.TransactionListener; @@ -45,6 +47,9 @@ public class ServerRuntimeIT extends ServerCase { @Inject private ServerRuntime runtime; + @Inject + private ObjectContext context; + @Test public void testPerformInTransaction_Local_Callback() { @@ -93,4 +98,31 @@ public class ServerRuntimeIT extends ServerCase { verify(callback, times(0)).willCommit(any(Transaction.class)); } } + + @Test + public void testRollbackTransaction() { + assertEquals(0, ObjectSelect.query(Artist.class).selectCount(context)); + + try { + runtime.performInTransaction(new TransactionalOperation<Object>() { + @Override + public Object perform() { + // Default PK batch size is 20 + for (int i = 0; i < 30; i++) { + Artist artist = context.newObject(Artist.class); + artist.setArtistName("test" + i); + context.commitChanges(); + } + + // this should fail with validation error + context.newObject(Artist.class); + context.commitChanges(); + return null; + } + }); + } catch (Exception ignored) { + } + + assertEquals(0, ObjectSelect.query(Artist.class).selectCount(context)); + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/4f4ade0e/cayenne-server/src/test/java/org/apache/cayenne/tx/UserTransactionIT.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/tx/UserTransactionIT.java b/cayenne-server/src/test/java/org/apache/cayenne/tx/UserTransactionIT.java index 9d1338f..3097808 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/tx/UserTransactionIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/tx/UserTransactionIT.java @@ -108,6 +108,11 @@ public class UserTransactionIT extends ServerCase { public void addListener(TransactionListener listener) { delegate.addListener(listener); } + + @Override + public boolean isExternal() { + return false; + } } }