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.
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 5c24e4e..c7c5b5a 100644
--- a/src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java
+++ b/src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java
@@ -49,6 +49,36 @@
}
@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);
+ }
+ }
+ }
+
+ @Override
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 68ca123..ce37fbe 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);
}
@@ -135,8 +154,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;
@@ -192,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<>();
+ 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<>();
+ 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/DialectMaxDBTest.java b/src/test/java/com/google/gwtorm/schema/sql/DialectMaxDBTest.java
index bea6ae8..9bab614 100644
--- a/src/test/java/com/google/gwtorm/schema/sql/DialectMaxDBTest.java
+++ b/src/test/java/com/google/gwtorm/schema/sql/DialectMaxDBTest.java
@@ -40,6 +40,8 @@
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Properties;
import java.util.Set;
@@ -79,14 +81,6 @@
new Database<PhoneBookDb>(new SimpleDataSource(p), PhoneBookDb.class);
phoneBook2 =
new Database<PhoneBookDb2>(new SimpleDataSource(p), PhoneBookDb2.class);
-
- drop("SEQUENCE address_id");
- drop("SEQUENCE cnt");
-
- drop("TABLE addresses");
- drop("TABLE foo");
- drop("TABLE bar");
- drop("TABLE people");
}
private void drop(String drop) {
@@ -98,6 +92,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();
}
@@ -326,4 +330,29 @@
}
}
+ @Test
+ public void testRollbackTransaction() throws SQLException, OrmException {
+ PhoneBookDb schema = phoneBook.open();
+ schema.updateSchema(executor);
+ schema.people().beginTransaction(null);
+ ArrayList<Person> all = new ArrayList<>();
+ 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<>();
+ 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 e20435f..b0c8db5 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);
}
@@ -220,4 +224,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<>();
+ 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<>();
+ 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 43f513d..bb4d7fb 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);
}
@@ -220,6 +224,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<>();
+ 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<>();
+ 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 ed20480..aae302f 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);
}
@@ -219,4 +223,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<>();
+ 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<>();
+ 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());
+ }
}