Add transaction support for Jdbc dialects
Transaction support is a no-op for Jdbc dialects.
In some rare cases it's however indispensable to have transaction
support, as in:
beginTransaction();
try {
insertPatchSetAncestors();
insertPatchSets();
updateChange();
commit();
} catch (OrmException e) {
rollback();
}
I assume that I65e111bed was trying to achieve just that. Make it work
also for Jdbc dialects and not only for NoSQL dialects.
Conflicts:
src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java
src/test/java/com/google/gwtorm/schema/sql/DialectMaxDBTest.java
(cherry picked from commit 1324d618941127d1b76cb22c96cb75ec73ab8fa7)
Bug: issue 2034
Bug: issue 2246
Bug: issue 2383
Bug: issue 2702
Change-Id: I29ab37e1cbc78468cb3f8f6abfd1bf54359e6090
diff --git a/src/main/java/com/google/gwtorm/jdbc/JdbcAccess.java b/src/main/java/com/google/gwtorm/jdbc/JdbcAccess.java
index 7e2a611..aaddfa3 100644
--- a/src/main/java/com/google/gwtorm/jdbc/JdbcAccess.java
+++ b/src/main/java/com/google/gwtorm/jdbc/JdbcAccess.java
@@ -39,6 +39,15 @@
}
@Override
+ public void beginTransaction(K key) throws OrmException {
+ try {
+ schema.getConnection().setAutoCommit(false);
+ } catch (SQLException e) {
+ throw convertError("beginTransaction", e);
+ }
+ }
+
+ @Override
public final com.google.gwtorm.server.ResultSet<T> get(final Iterable<K> keys)
throws OrmException {
final Collection<K> keySet;
diff --git a/src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java b/src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java
index 60100a2..00310e4 100644
--- a/src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java
+++ b/src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java
@@ -27,7 +27,6 @@
import java.sql.Connection;
import java.sql.SQLException;
-import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;
@@ -49,6 +48,36 @@
return dbDef.getDialect();
}
+ @Override
+ public void commit() throws OrmException {
+ try {
+ conn.commit();
+ } catch (SQLException err) {
+ throw new OrmException("Cannot commit transaction", err);
+ } finally {
+ try {
+ conn.setAutoCommit(true);
+ } catch (SQLException err) {
+ throw new OrmException("Cannot set auto commit mode", err);
+ }
+ }
+ }
+
+ @Override
+ public void rollback() throws OrmException {
+ try {
+ conn.rollback();
+ } catch (SQLException err) {
+ throw new OrmException("Cannot rollback transaction", err);
+ } finally {
+ try {
+ conn.setAutoCommit(true);
+ } catch (SQLException err) {
+ throw new OrmException("Cannot set auto commit mode", err);
+ }
+ }
+ }
+
public void updateSchema(final StatementExecutor e) throws OrmException {
try {
createSequences(e);
diff --git a/src/test/java/com/google/gwtorm/schema/sql/DialectH2Test.java b/src/test/java/com/google/gwtorm/schema/sql/DialectH2Test.java
index 8e332b4..db674fa 100644
--- a/src/test/java/com/google/gwtorm/schema/sql/DialectH2Test.java
+++ b/src/test/java/com/google/gwtorm/schema/sql/DialectH2Test.java
@@ -35,7 +35,9 @@
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.Properties;
import java.util.Set;
@@ -64,6 +66,16 @@
@After
public void tearDown() {
+ // Database content must be flushed because
+ // tests assume that the database is empty
+ drop("SEQUENCE address_id");
+ drop("SEQUENCE cnt");
+
+ drop("TABLE addresses");
+ drop("TABLE foo");
+ drop("TABLE bar");
+ drop("TABLE people");
+
if (executor != null) {
executor.close();
}
@@ -79,6 +91,13 @@
db = null;
}
+ private void drop(String drop) {
+ try {
+ execute("DROP " + drop);
+ } catch (OrmException e) {
+ }
+ }
+
private void execute(final String sql) throws OrmException {
executor.execute(sql);
}
@@ -120,8 +139,6 @@
execute("ALTER TABLE people ADD COLUMN fake_name VARCHAR(20)");
execute("ALTER TABLE people DROP COLUMN registered");
- execute("DROP TABLE addresses");
- execute("DROP SEQUENCE address_id");
Set<String> sequences, tables;
@@ -177,4 +194,30 @@
assertTrue(s.contains("bar"));
assertFalse(s.contains("for"));
}
+
+ @Test
+ public void testRollbackTransaction() throws SQLException, OrmException {
+ PhoneBookDb schema = phoneBook.open();
+ schema.updateSchema(executor);
+ schema.people().beginTransaction(null);
+ ArrayList<Person> all = new ArrayList<Person>();
+ all.add(new Person(new Person.Key("Bob"), 18));
+ schema.people().insert(all);
+ schema.rollback();
+ List<Person> r = schema.people().olderThan(10).toList();
+ assertEquals(0, r.size());
+ }
+
+ @Test
+ public void testCommitTransaction() throws SQLException, OrmException {
+ PhoneBookDb schema = phoneBook.open();
+ schema.updateSchema(executor);
+ schema.people().beginTransaction(null);
+ ArrayList<Person> all = new ArrayList<Person>();
+ all.add(new Person(new Person.Key("Bob"), 18));
+ schema.people().insert(all);
+ schema.commit();
+ List<Person> r = schema.people().olderThan(10).toList();
+ assertEquals(1, r.size());
+ }
}
diff --git a/src/test/java/com/google/gwtorm/schema/sql/DialectMySQLTest.java b/src/test/java/com/google/gwtorm/schema/sql/DialectMySQLTest.java
index a2d3abc..186134a 100644
--- a/src/test/java/com/google/gwtorm/schema/sql/DialectMySQLTest.java
+++ b/src/test/java/com/google/gwtorm/schema/sql/DialectMySQLTest.java
@@ -37,7 +37,9 @@
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.Properties;
import java.util.Set;
@@ -75,24 +77,19 @@
new Database<PhoneBookDb>(new SimpleDataSource(p), PhoneBookDb.class);
phoneBook2 =
new Database<PhoneBookDb2>(new SimpleDataSource(p), PhoneBookDb2.class);
+ }
+ @After
+ public void tearDown() {
+ // Database content must be flushed because
+ // tests assume that the database is empty
drop("TABLE address_id");
drop("TABLE addresses");
drop("TABLE cnt");
drop("TABLE bar");
drop("TABLE foo");
drop("TABLE people");
- }
- private void drop(String drop) {
- try {
- execute("DROP " + drop);
- } catch (OrmException e) {
- }
- }
-
- @After
- public void tearDown() {
if (executor != null) {
executor.close();
}
@@ -108,6 +105,13 @@
db = null;
}
+ private void drop(String drop) {
+ try {
+ execute("DROP " + drop);
+ } catch (OrmException e) {
+ }
+ }
+
private void execute(final String sql) throws OrmException {
executor.execute(sql);
}
@@ -206,4 +210,30 @@
assertTrue(s.contains("bar"));
assertFalse(s.contains("for"));
}
+
+ @Test
+ public void testRollbackTransaction() throws SQLException, OrmException {
+ PhoneBookDb schema = phoneBook.open();
+ schema.updateSchema(executor);
+ schema.people().beginTransaction(null);
+ ArrayList<Person> all = new ArrayList<Person>();
+ all.add(new Person(new Person.Key("Bob"), 18));
+ schema.people().insert(all);
+ schema.rollback();
+ List<Person> r = schema.people().olderThan(10).toList();
+ assertEquals(0, r.size());
+ }
+
+ @Test
+ public void testCommitTransaction() throws SQLException, OrmException {
+ PhoneBookDb schema = phoneBook.open();
+ schema.updateSchema(executor);
+ schema.people().beginTransaction(null);
+ ArrayList<Person> all = new ArrayList<Person>();
+ all.add(new Person(new Person.Key("Bob"), 18));
+ schema.people().insert(all);
+ schema.commit();
+ List<Person> r = schema.people().olderThan(10).toList();
+ assertEquals(1, r.size());
+ }
}
diff --git a/src/test/java/com/google/gwtorm/schema/sql/DialectOracleSQLTest.java b/src/test/java/com/google/gwtorm/schema/sql/DialectOracleSQLTest.java
index 21a0ac6..8f75bb1 100644
--- a/src/test/java/com/google/gwtorm/schema/sql/DialectOracleSQLTest.java
+++ b/src/test/java/com/google/gwtorm/schema/sql/DialectOracleSQLTest.java
@@ -36,7 +36,9 @@
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.Properties;
import java.util.Set;
@@ -74,7 +76,12 @@
new Database<PhoneBookDb>(new SimpleDataSource(p), PhoneBookDb.class);
phoneBook2 =
new Database<PhoneBookDb2>(new SimpleDataSource(p), PhoneBookDb2.class);
+ }
+ @After
+ public void tearDown() {
+ // Database content must be flushed because
+ // tests assume that the database is empty
drop("SEQUENCE address_id");
drop("SEQUENCE cnt");
@@ -82,17 +89,7 @@
drop("TABLE foo");
drop("TABLE bar");
drop("TABLE people");
- }
- private void drop(String drop) {
- try {
- execute("DROP " + drop);
- } catch (OrmException e) {
- }
- }
-
- @After
- public void tearDown() {
if (executor != null) {
executor.close();
}
@@ -108,6 +105,13 @@
db = null;
}
+ private void drop(String drop) {
+ try {
+ execute("DROP " + drop);
+ } catch (OrmException e) {
+ }
+ }
+
private void execute(final String sql) throws OrmException {
executor.execute(sql);
}
@@ -205,6 +209,31 @@
s = dialect.listTables(db);
assertTrue(s.contains("bar"));
assertFalse(s.contains("for"));
+ }
+ @Test
+ public void testRollbackTransaction() throws SQLException, OrmException {
+ PhoneBookDb schema = phoneBook.open();
+ schema.updateSchema(executor);
+ schema.people().beginTransaction(null);
+ ArrayList<Person> all = new ArrayList<Person>();
+ all.add(new Person(new Person.Key("Bob"), 18));
+ schema.people().insert(all);
+ schema.rollback();
+ List<Person> r = schema.people().olderThan(10).toList();
+ assertEquals(0, r.size());
+ }
+
+ @Test
+ public void testCommitTransaction() throws SQLException, OrmException {
+ PhoneBookDb schema = phoneBook.open();
+ schema.updateSchema(executor);
+ schema.people().beginTransaction(null);
+ ArrayList<Person> all = new ArrayList<Person>();
+ all.add(new Person(new Person.Key("Bob"), 18));
+ schema.people().insert(all);
+ schema.commit();
+ List<Person> r = schema.people().olderThan(10).toList();
+ assertEquals(1, r.size());
}
}
diff --git a/src/test/java/com/google/gwtorm/schema/sql/DialectPostgreSQLTest.java b/src/test/java/com/google/gwtorm/schema/sql/DialectPostgreSQLTest.java
index e68d469..0330b18 100644
--- a/src/test/java/com/google/gwtorm/schema/sql/DialectPostgreSQLTest.java
+++ b/src/test/java/com/google/gwtorm/schema/sql/DialectPostgreSQLTest.java
@@ -37,7 +37,9 @@
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.Properties;
import java.util.Set;
@@ -73,7 +75,12 @@
new Database<PhoneBookDb>(new SimpleDataSource(p), PhoneBookDb.class);
phoneBook2 =
new Database<PhoneBookDb2>(new SimpleDataSource(p), PhoneBookDb2.class);
+ }
+ @After
+ public void tearDown() {
+ // Database content must be flushed because
+ // tests assume that the database is empty
drop("SEQUENCE address_id");
drop("SEQUENCE cnt");
@@ -81,17 +88,7 @@
drop("TABLE foo");
drop("TABLE bar");
drop("TABLE people");
- }
- private void drop(String drop) {
- try {
- execute("DROP " + drop);
- } catch (OrmException e) {
- }
- }
-
- @After
- public void tearDown() {
if (executor != null) {
executor.close();
}
@@ -107,6 +104,13 @@
db = null;
}
+ private void drop(String drop) {
+ try {
+ execute("DROP " + drop);
+ } catch (OrmException e) {
+ }
+ }
+
private void execute(final String sql) throws OrmException {
executor.execute(sql);
}
@@ -205,4 +209,30 @@
assertTrue(s.contains("bar"));
assertFalse(s.contains("for"));
}
+
+ @Test
+ public void testRollbackTransaction() throws SQLException, OrmException {
+ PhoneBookDb schema = phoneBook.open();
+ schema.updateSchema(executor);
+ schema.people().beginTransaction(null);
+ ArrayList<Person> all = new ArrayList<Person>();
+ all.add(new Person(new Person.Key("Bob"), 18));
+ schema.people().insert(all);
+ schema.rollback();
+ List<Person> r = schema.people().olderThan(10).toList();
+ assertEquals(0, r.size());
+ }
+
+ @Test
+ public void testCommitTransaction() throws SQLException, OrmException {
+ PhoneBookDb schema = phoneBook.open();
+ schema.updateSchema(executor);
+ schema.people().beginTransaction(null);
+ ArrayList<Person> all = new ArrayList<Person>();
+ all.add(new Person(new Person.Key("Bob"), 18));
+ schema.people().insert(all);
+ schema.commit();
+ List<Person> r = schema.people().olderThan(10).toList();
+ assertEquals(1, r.size());
+ }
}