You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2017/02/20 08:43:45 UTC

cayenne git commit: CAY-2186 Always run MySQL PK generator in separate transaction

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 <st...@gmail.com>
Authored: Mon Feb 20 11:43:17 2017 +0300
Committer: Nikita Timofeev <st...@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;
+        }
     }
 
 }