#919 - io.ebean package initial

This commit is contained in:
Rob Bygrave
2016-12-11 23:23:22 +13:00
parent 5821dc96b9
commit 971e2dc91b
2134 changed files with 10721 additions and 8652 deletions
@@ -0,0 +1,95 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.EbeanServer;
import io.ebean.EbeanServerFactory;
import io.ebean.Query;
import io.ebean.Transaction;
import io.ebean.config.PropertyMap;
import io.ebean.config.ServerConfig;
import org.tests.model.basic.UTDetail;
import org.tests.model.basic.UTMaster;
import org.avaje.datasource.DataSourceConfig;
import org.avaje.datasource.DataSourcePool;
import org.avaje.datasource.pool.ConnectionPool;
import org.junit.Test;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class TestAutoCommitDataSource extends BaseTestCase {
@Test
public void test() throws SQLException {
Properties properties = PropertyMap.defaultProperties();
DataSourceConfig dsConfig = new DataSourceConfig();
dsConfig.loadSettings(properties, "h2autocommit");//"pg"
dsConfig.setAutoCommit(true);
DataSourcePool pool = new ConnectionPool("h2autocommit", dsConfig);
Connection connection = pool.getConnection();
assertTrue(connection.getAutoCommit());
connection.close();
System.setProperty("ebean.ignoreExtraDdl", "true");
ServerConfig config = new ServerConfig();
config.setName("h2autocommit");
config.setH2ProductionMode(true);
config.loadFromProperties();
config.setDataSource(pool);
config.setDefaultServer(false);
config.setRegister(false);
config.addClass(UTMaster.class);
config.addClass(UTDetail.class);
config.setDdlGenerate(true);
config.setDdlRun(true);
config.setAutoCommitMode(true);
EbeanServer ebeanServer = EbeanServerFactory.create(config);
Query<UTMaster> query = ebeanServer.find(UTMaster.class);
List<UTMaster> details = ebeanServer.findList(query, null);
assertEquals(0, details.size());
UTMaster bean1 = new UTMaster("one1");
UTMaster bean2 = new UTMaster("two2");
UTMaster bean3 = new UTMaster("three3");
// use a different transaction to do final query check
Transaction otherTxn = ebeanServer.createTransaction();
Transaction txn = ebeanServer.beginTransaction();
assertTrue(txn.getConnection().getAutoCommit());
try {
ebeanServer.save(bean1);
ebeanServer.save(bean2);
Query<UTMaster> query2 = ebeanServer.find(UTMaster.class);
details = ebeanServer.findList(query2, otherTxn);
assertEquals(2, details.size());
ebeanServer.save(bean3);
txn.rollback();
} finally {
txn.end();
}
Query<UTMaster> query3 = ebeanServer.find(UTMaster.class);
details = ebeanServer.findList(query3, otherTxn);
assertEquals(3, details.size());
}
}
@@ -0,0 +1,133 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.EbeanServer;
import io.ebean.Transaction;
import io.ebean.PersistBatch;
import org.tests.model.basic.UTDetail;
import org.tests.model.basic.UTMaster;
import org.avaje.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import static org.junit.Assert.assertTrue;
public class TestBatchPersistCascade extends BaseTestCase {
Logger logger = LoggerFactory.getLogger(TestBatchPersistCascade.class);
@Test
public void test() {
if (isMsSqlServer()) return;
EbeanServer ebeanServer = Ebean.getServer(null);
LoggedSqlCollector.start();
Transaction txn = ebeanServer.beginTransaction();
try {
txn.setBatch(PersistBatch.INSERT);
logger.info("start ------------");
for (int i = 0; i < 3; i++) {
UTMaster master = createMaster(i);
logger.info("save ------------ {}", i);
ebeanServer.save(master);
//txn.flushBatch();
}
logger.info("commit ------------");
txn.commit();
} finally {
txn.end();
}
List<String> loggedSql = LoggedSqlCollector.stop();
assertTrue(loggedSql.size() > 2);
testUpdates();
}
private void testUpdates() {
EbeanServer server = Ebean.getServer(null);
List<UTMaster> list = server.find(UTMaster.class).fetch("details").findList();
Transaction txn = server.beginTransaction();
try {
txn.setBatch(PersistBatch.INSERT);
txn.setBatchOnCascade(PersistBatch.ALL);
for (int i = 0; i < 3; i++) {
UTMaster master = createMaster(i + 500);
logger.info("save ------------ {}", i);
server.save(master);
}
logger.info("starting updates ------------ ");
UTMaster lastMaster = null;
for (UTMaster utMaster : list) {
utMaster.setName(utMaster.getName() + " + mod");
List<UTDetail> details = utMaster.getDetails();
for (UTDetail detail : details) {
detail.setQty(detail.getQty() + 7);
detail.setName(detail.getName() + " + foo");
}
server.save(utMaster);
lastMaster = utMaster;
}
logger.info("starting some inserts ------------ ");
for (int i = 0; i < 3; i++) {
UTMaster master = createMaster(i + 1000);
logger.info("save ------------ {}", i);
server.save(master);
if (i == 1) {
logger.info("save lastMaster ------------ ");
lastMaster.setName("mod");
server.save(lastMaster);
}
}
logger.info("commit ------------ ");
server.commitTransaction();
} finally {
server.endTransaction();
}
}
private UTDetail createUTDetail(String master, int count) {
UTDetail detail = new UTDetail();
detail.setName(master + "-" + count);
detail.setAmount(50d);
detail.setQty(count);
return detail;
}
private UTMaster createMaster(int count) {
String name = "master" + count;
UTMaster m0 = new UTMaster();
m0.setName(name);
for (int i = 0; i < 5; i++) {
m0.addDetail(createUTDetail(name, i));
}
return m0;
}
}
@@ -0,0 +1,99 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.Transaction;
import org.tests.model.m2m.MnyB;
import org.tests.model.m2m.MnyC;
import org.avaje.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
public class TestBeanStateReset extends BaseTestCase {
private static final Logger logger = LoggerFactory.getLogger(TestBeanStateReset.class);
@Test
public void resetForInsert() {
// setup to fail foreign key constraint
MnyC c = new MnyC();
c.setId(Long.MAX_VALUE);
MnyB b = new MnyB();
b.getCs().add(c);
try {
// inserts of b succeeds but intersection insert fails FK check on c
b.save();
} catch (PersistenceException e) {
logger.info("expected error " + e.getMessage());
Ebean.getBeanState(b).resetForInsert();
b.getCs().clear();
LoggedSqlCollector.start();
b.setName("mod");
b.save();
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql.get(0)).contains("insert into mny_b (id, name, version, when_created, when_modified, a_id) values (");
}
}
@Test
public void alternativeVia_persistCascadeOff_with_commitAndContinue() {
// setup to fail foreign key constraint when using cascade save
MnyC c = new MnyC();
c.setId(Long.MAX_VALUE);
MnyB b = new MnyB();
b.getCs().add(c);
Transaction transaction = Ebean.beginTransaction();
try {
// turn off cascade ...
transaction.setPersistCascade(false);
b.save();
// commit at this point
transaction.commitAndContinue();
try {
// turn on cascade ... such that the ManyToMany is persisted
transaction.setPersistCascade(true);
// save b again which this time cascades to the ManyToMany
// but this fails due to FK on ManyToMany
b.save();
// we actually don't get here due to the FK error
transaction.commit();
} catch (PersistenceException e) {
// so we failed the second save but that is ok'ish
// we handle this exception knowing b got inserted and committed
// and that the inserts into the intersection table failed
logger.info("The ManyToMany intersection error: " + e.getMessage());
}
} finally {
// performs a rollback as the commit at line:80 does not happen
transaction.end();
}
// assert our insert prior to the commitAndContinue succeeded
MnyB madeIt = Ebean.find(MnyB.class, b.getId());
assertNotNull(madeIt);
}
}
@@ -0,0 +1,39 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.Transaction;
import io.ebean.TxIsolation;
import org.junit.Test;
import javax.persistence.PersistenceException;
import java.sql.Connection;
import static org.junit.Assert.assertEquals;
public class TestBeginTransactionWithExisting extends BaseTestCase {
@Test
public void testTransactionIsoLevels() {
assertEquals(Transaction.READ_COMMITTED, Connection.TRANSACTION_READ_COMMITTED);
assertEquals(Transaction.READ_UNCOMMITTED, Connection.TRANSACTION_READ_UNCOMMITTED);
assertEquals(Transaction.REPEATABLE_READ, Connection.TRANSACTION_REPEATABLE_READ);
assertEquals(Transaction.SERIALIZABLE, Connection.TRANSACTION_SERIALIZABLE);
}
@Test(expected = PersistenceException.class)
public void test() {
assertEquals(Transaction.READ_COMMITTED, Connection.TRANSACTION_READ_COMMITTED);
Transaction txn = Ebean.beginTransaction();
try {
Ebean.beginTransaction(TxIsolation.READ_COMMITED);
} finally {
txn.end();
}
}
}
@@ -0,0 +1,183 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.EbeanServer;
import io.ebean.Transaction;
import io.ebean.annotation.Transactional;
import org.tests.model.m2m.MnyB;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
public class TestCommitAndContinue extends BaseTestCase {
private static final Logger logger = LoggerFactory.getLogger("org.avaje.ebean.TXN");
@Test
@Transactional
public void transactional_partialSuccess() {
MnyB a = new MnyB("a100");
MnyB b = new MnyB("b200");
a.save();
// commit at this point
Ebean.currentTransaction().commitAndContinue();
try {
b.save();
// some error occurs
throw new IllegalStateException();
} catch (IllegalStateException e) {
// mark the transaction as rollback
Ebean.currentTransaction().setRollbackOnly();
// use a different transaction to assert
EbeanServer server = Ebean.getDefaultServer();
Transaction anotherTxn = server.createTransaction();
// success prior to commitAndContinue
assertNotNull(server.find(MnyB.class, a.getId(), anotherTxn));
// insert failed after commitAndContinue
assertNull(server.find(MnyB.class, b.getId(), anotherTxn));
}
}
/**
* The @Transactional is nicer to me.
*/
@Test
public void tryFinally_partialSuccess() {
MnyB a = new MnyB("a100");
MnyB b = new MnyB("b200");
EbeanServer server = Ebean.getDefaultServer();
Transaction txn = server.beginTransaction();
try {
a.save();
// commit at this point
txn.commitAndContinue();
try {
b.save();
// some error occurs
throw new IllegalStateException();
} catch (IllegalStateException e) {
// mark the transaction as rollback
txn.setRollbackOnly();
// use a different transaction to assert
Transaction anotherTxn = server.createTransaction();
// success prior to commitAndContinue
assertNotNull(server.find(MnyB.class, a.getId(), anotherTxn));
// insert failed after commitAndContinue
assertNull(server.find(MnyB.class, b.getId(), anotherTxn));
}
// does not commit due to the txn.setRollbackOnly();
txn.commit();
} finally {
server.endTransaction();
}
}
@Test
@Transactional
public void transactional_partialSuccess_secondTransactionInsert() {
MnyB a = new MnyB("a100");
MnyB b = new MnyB("b200");
MnyB c = new MnyB("c300");
a.save();
// commit at this point
Ebean.currentTransaction().commitAndContinue();
try {
b.save();
// some error occurs
throw new IllegalStateException();
} catch (IllegalStateException e) {
// mark the transaction as rollback
Ebean.currentTransaction().setRollbackOnly();
// use a different transaction to do something useful
EbeanServer server = Ebean.getDefaultServer();
Transaction txn2 = server.createTransaction();
try {
server.save(c, txn2);
txn2.commit();
} finally {
txn2.end();
}
}
// asserts
EbeanServer server = Ebean.getDefaultServer();
Transaction txnForAssert = server.createTransaction();
// success prior to commitAndContinue
assertNotNull(server.find(MnyB.class, a.getId(), txnForAssert));
// insert failed after commitAndContinue
assertNull(server.find(MnyB.class, b.getId(), txnForAssert));
// successful insert using txn2
assertNotNull(server.find(MnyB.class, c.getId(), txnForAssert));
}
@Test
public void basic() {
MnyB a = new MnyB("a");
MnyB b = new MnyB("b");
MnyB c = new MnyB("c");
Transaction txn = Ebean.beginTransaction();
try {
a.save();
txn.commitAndContinue();
txn.setBatchMode(true);
b.save();
logger.info("... pre commitAndContinue");
txn.commitAndContinue();
c.save();
txn.commit();
} finally {
txn.end();
}
}
@Test
@Transactional
public void runTransactional() {
new MnyB("a100").save();
new MnyB("a101").save();
Ebean.currentTransaction().commitAndContinue();
new MnyB("a200").save();
new MnyB("a201").save();
}
}
@@ -0,0 +1,17 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import org.junit.Test;
public class TestCreateTransactionWithIsolation extends BaseTestCase {
@Test
public void test() {
// EbeanServer server = Ebean.getServer(null);
// Transaction txn = server.createTransaction(TxIsolation.SERIALIZABLE);
// txn.end();
}
}
@@ -0,0 +1,57 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebeaninternal.api.SpiTransaction;
import org.tests.model.basic.EBasicVer;
import org.tests.model.basic.ResetBasicData;
import org.junit.Test;
import static junit.framework.TestCase.assertNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
public class TestDeleteFromPersistenceContext extends BaseTestCase {
@Test
public void testDeleteBean() {
ResetBasicData.reset();
EBasicVer bean = new EBasicVer("Please Delete Me");
Ebean.save(bean);
SpiTransaction transaction = (SpiTransaction) Ebean.beginTransaction();
try {
EBasicVer bean2 = Ebean.find(EBasicVer.class, bean.getId());
assertNotSame(bean, bean2);
EBasicVer bean3 = Ebean.find(EBasicVer.class, bean.getId());
// same instance from PersistenceContext
assertSame(bean2, bean3);
Object bean4 = transaction.getPersistenceContext().get(EBasicVer.class, bean.getId());
assertSame(bean2, bean4);
Ebean.delete(bean2);
Object bean5 = transaction.getPersistenceContext().get(EBasicVer.class, bean.getId());
assertNull("Bean is deleted from PersistenceContext", bean5);
Ebean.commitTransaction();
} finally {
Ebean.endTransaction();
}
EBasicVer bean6 = Ebean.find(EBasicVer.class).where().eq("id", bean.getId()).findUnique();
assertNull("Bean where id eq is not found " + bean6, bean6);
awaitL2Cache();
EBasicVer bean7 = Ebean.find(EBasicVer.class, bean.getId());
assertNull("Bean is not expected to be found? " + bean7, bean7);
}
}
@@ -0,0 +1,105 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.EbeanServer;
import io.ebean.EbeanServerFactory;
import io.ebean.Query;
import io.ebean.Transaction;
import io.ebean.config.PropertyMap;
import io.ebean.config.ServerConfig;
import org.tests.model.basic.UTDetail;
import org.tests.model.basic.UTMaster;
import org.avaje.datasource.DataSourceConfig;
import org.avaje.datasource.DataSourcePool;
import org.avaje.datasource.pool.ConnectionPool;
import org.junit.Test;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class TestExplicitTransactionMode extends BaseTestCase {
@Test
public void test() throws SQLException {
Properties properties = PropertyMap.defaultProperties();
DataSourceConfig dsConfig = new DataSourceConfig();
dsConfig.loadSettings(properties, "h2autocommit");//"h2autocommit","pg"
dsConfig.setAutoCommit(true);
DataSourcePool pool = new ConnectionPool("h2autocommit", dsConfig);
Connection connection = pool.getConnection();
assertTrue(connection.getAutoCommit());
connection.close();
System.setProperty("ebean.ignoreExtraDdl", "true");
ServerConfig config = new ServerConfig();
config.setName("h2autocommit");
config.loadFromProperties();
config.setDataSource(pool);
config.setDefaultServer(false);
config.setRegister(false);
config.setExplicitTransactionBeginMode(true);
config.addClass(UTMaster.class);
config.addClass(UTDetail.class);
config.setDdlGenerate(true);
config.setDdlRun(true);
EbeanServer ebeanServer = EbeanServerFactory.create(config);
Query<UTMaster> query = ebeanServer.find(UTMaster.class);
List<UTMaster> details = ebeanServer.findList(query, null);
assertEquals(0, details.size());
UTMaster bean0 = new UTMaster("one0");
Transaction txn0 = ebeanServer.beginTransaction();
try {
ebeanServer.save(bean0);
txn0.rollback();
} finally {
txn0.end();
}
// rollback as expected
assertEquals(0, ebeanServer.find(UTMaster.class).findCount());
UTMaster bean1 = new UTMaster("one1");
UTMaster bean2 = new UTMaster("two2");
UTMaster bean3 = new UTMaster("three3");
// use a different transaction to do final query check
Transaction otherTxn = ebeanServer.createTransaction();
Transaction txn = ebeanServer.beginTransaction();
try {
ebeanServer.save(bean1);
ebeanServer.save(bean2);
// not visible in other transaction
Query<UTMaster> query2 = ebeanServer.find(UTMaster.class);
details = ebeanServer.findList(query2, otherTxn);
assertEquals(0, details.size());
ebeanServer.save(bean3);
txn.commit();
} finally {
txn.end();
}
// commit as expected
Query<UTMaster> query3 = ebeanServer.find(UTMaster.class);
details = ebeanServer.findList(query3, otherTxn);
assertEquals(3, details.size());
}
}
@@ -0,0 +1,55 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import org.tests.model.basic.BBookmark;
import org.tests.model.basic.BBookmarkUser;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class TestInsertManyAndRef extends BaseTestCase {
@Test
public void testMe() {
// ResetBasicData.reset();
//
// Customer u = new Customer();
// u.setName("Mr Test");
//
// final List<Order> bookmarks = new ArrayList<Order>();
// final Order b1 = new Order();
// b1.setCustomer(u);
// b1.setStatus(Status.NEW);
//
// final Order b2 = new Order();
// b2.setStatus(Status.NEW);
// b2.setCustomer(u);
//
// bookmarks.add(b1);
// bookmarks.add(b2);
//
// Ebean.save(bookmarks);
final BBookmarkUser u = new BBookmarkUser();
u.setEmailAddress("test@test.com");
u.setName("Mr Test");
u.setPassword("password");
final List<BBookmark> bookmarks = new ArrayList<>();
final BBookmark b1 = new BBookmark();
b1.setBookmarkReference("Acts 2:7-20");
b1.setUser(u);
final BBookmark b2 = new BBookmark();
b2.setBookmarkReference("Acts 7:1-20");
b2.setUser(u);
bookmarks.add(b1);
bookmarks.add(b2);
Ebean.saveAll(bookmarks);
}
}
@@ -0,0 +1,31 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.TxRunnable;
import org.junit.Assert;
import org.junit.Test;
public class TestNested extends BaseTestCase {
@Test
public void test() {
try {
Ebean.execute(() -> willFail());
} catch (RuntimeException e) {
Assert.assertEquals(e.getMessage(), "test rollback");
}
}
private void willFail() {
Ebean.execute(new TxRunnable() {
public void run() {
String msg = "test rollback";
throw new RuntimeException(msg);
}
});
}
}
@@ -0,0 +1,62 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.EbeanServer;
import io.ebean.Transaction;
import io.ebean.TxScope;
import org.tests.model.basic.Country;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Product;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestNestedBeginRequired extends BaseTestCase {
Logger logger = LoggerFactory.getLogger(TestNestedBeginRequired.class);
EbeanServer server = Ebean.getServer(null);
@Test
public void test() {
someOuterMethod();
}
private void someOuterMethod() {
Transaction txn = server.beginTransaction(TxScope.required());
try {
server.find(Country.class).findCount();
someInnerMethod();
server.find(Product.class).findCount();
txn.commit();
} finally {
txn.end();
}
}
private void someInnerMethod() {
logger.debug("someInnerMethod() ...");
Transaction txn = server.beginTransaction(TxScope.required());
try {
server.find(Customer.class).findCount();
txn.commit();
} finally {
txn.end();
}
logger.debug("someInnerMethod() ... done");
}
}
@@ -0,0 +1,77 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.EbeanServer;
import io.ebean.Transaction;
import io.ebean.TxScope;
import org.tests.model.basic.Country;
import org.tests.model.basic.Customer;
import org.tests.model.basic.EBasic;
import org.tests.model.basic.Product;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestNestedBeginRequiredWithFailure extends BaseTestCase {
Logger logger = LoggerFactory.getLogger(TestNestedBeginRequiredWithFailure.class);
EbeanServer server = Ebean.getServer(null);
@Test
public void test() {
someOuterMethod();
}
private void someOuterMethod() {
Transaction txn = server.beginTransaction(TxScope.required());
try {
server.find(Country.class).findCount();
try {
someInnerMethodWithFailure();
server.find(Product.class).findCount();
txn.commit();
} catch (RuntimeException e) {
logger.info("Inner method failed with " + e);
}
} finally {
// For REQUIRED ... the transaction can already been
// rolled back (by inner method) so that case is expected
// (and that is the case here - txn is already rolled back)
txn.end();
}
}
private void someInnerMethodWithFailure() {
logger.debug("someInnerMethod() ...");
Transaction txn = server.beginTransaction(TxScope.required());
try {
server.find(Customer.class).findCount();
EBasic basic = new EBasic();
basic.setName("ignore");
server.save(basic);
if (server != null) {
throw new RuntimeException("barf");
}
txn.commit();
} finally {
txn.end();
logger.debug("someInnerMethod() ... done");
}
}
}
@@ -0,0 +1,61 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.EbeanServer;
import io.ebean.Transaction;
import io.ebean.TxScope;
import org.tests.model.basic.Country;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Product;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestNestedBeginRequiresNew extends BaseTestCase {
Logger logger = LoggerFactory.getLogger(TestNestedBeginRequiresNew.class);
EbeanServer server = Ebean.getServer(null);
@Test
public void test() {
someOuterMethod();
}
private void someOuterMethod() {
Transaction txn = server.beginTransaction(TxScope.requiresNew());
try {
server.find(Country.class).findCount();
someInnerMethod();
server.find(Product.class).findCount();
txn.commit();
} finally {
txn.end();
}
}
private void someInnerMethod() {
logger.debug("someInnerMethod() ...");
Transaction txn = server.beginTransaction(TxScope.requiresNew());
try {
server.find(Customer.class).findCount();
txn.commit();
} finally {
txn.end();
}
logger.debug("someInnerMethod() ... done");
}
}
@@ -0,0 +1,67 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.EbeanServer;
import io.ebean.Transaction;
import io.ebean.TxScope;
import org.tests.model.basic.Country;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Product;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestNestedBeginRequiresNewWithFailure extends BaseTestCase {
Logger logger = LoggerFactory.getLogger(TestNestedBeginRequiresNewWithFailure.class);
EbeanServer server = Ebean.getServer(null);
@Test
public void test() {
someOuterMethod();
}
private void someOuterMethod() {
Transaction txn = server.beginTransaction(TxScope.requiresNew());
try {
server.find(Country.class).findCount();
try {
someInnerMethodWithFailure();
} catch (RuntimeException e) {
logger.info("Inner method failed with " + e.getMessage());
}
server.find(Product.class).findCount();
txn.commit();
} finally {
txn.end();
}
}
private void someInnerMethodWithFailure() {
logger.debug("someInnerMethod() ...");
Transaction txn = server.beginTransaction(TxScope.requiresNew());
try {
server.find(Customer.class).findCount();
if (server != null) {
throw new RuntimeException("barf");
}
txn.commit();
} finally {
txn.end();
}
logger.debug("someInnerMethod() ... done");
}
}
@@ -0,0 +1,78 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.EbeanServer;
import io.ebean.Transaction;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.api.SpiTransaction;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
public class TestPersistContextClear extends BaseTestCase {
@Test
public void test() {
ResetBasicData.reset();
ResetBasicData.createOrderCustAndOrder("testPc");
Transaction t = Ebean.beginTransaction();
SpiTransaction spiTxn = (SpiTransaction) t;
PersistenceContext pc = spiTxn.getPersistenceContext();
// no orders or customers in the PC
Assert.assertEquals(0, pc.size(Order.class));
Assert.assertEquals(0, pc.size(Customer.class));
Order order0 = null;
try {
EbeanServer server = Ebean.getServer(null);
List<Order> list = server.find(Order.class).fetch("customer").fetch("details").findList();
int orderSize = list.size();
Assert.assertTrue(orderSize > 1);
// keep a hold of one of them
order0 = list.get(0);
Assert.assertEquals(orderSize, pc.size(Order.class));
System.gc();
Assert.assertEquals(orderSize, pc.size(Order.class));
Assert.assertTrue(pc.size(Customer.class) > 0);
list = null;
// System.gc();
// transaction still holds PC ...
// System.out.println("pc2:"+pc);
// These asserts may not succeed depending on JVM
// Assert.assertEquals(pc.size(Order.class), 1);
// Assert.assertEquals(pc.size(Customer.class), 1);
} finally {
t.end();
}
System.gc();
// we still have the order
Assert.assertNotNull(order0);
// its likely the only one in the PC now
// due to the System.gc(); but can't garuntee it
// so removing these asserts... can put them back
// to manually test.
// Assert.assertEquals(pc.size(Order.class), 1);
// Assert.assertEquals(pc.size(Customer.class), 1);
}
}
@@ -0,0 +1,38 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import org.tests.model.basic.EBasic;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class TestStatelessUpdateClearPC extends BaseTestCase {
@Test
public void test() {
Ebean.beginTransaction();
EBasic newUser = new EBasic();
newUser.setName("any@email.com");
Ebean.save(newUser);
// load the bean into the persistence context
EBasic dummyLoadedUser = Ebean.find(EBasic.class, newUser.getId()); // This row is added
assertNotNull(dummyLoadedUser);
// stateless update (should clear the bean from the persistence context)
EBasic updateUser = new EBasic();
updateUser.setId(newUser.getId());
updateUser.setName("anyNew@email.com");
Ebean.update(updateUser);
EBasic loadedUser = Ebean.find(EBasic.class, newUser.getId());
assertEquals("anyNew@email.com", loadedUser.getName());
Ebean.rollbackTransaction();
}
}
@@ -0,0 +1,83 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.EbeanServer;
import io.ebean.Transaction;
import io.ebean.TransactionCallbackAdapter;
import org.junit.Test;
import javax.persistence.PersistenceException;
import static org.junit.Assert.assertEquals;
public class TestTransactionCallback extends BaseTestCase {
int countPreCommit;
int countPostCommit;
int countPreRollback;
int countPostRollback;
@Test(expected = PersistenceException.class)
public void test_noActiveTransaction() {
Ebean.register(new MyCallback());
}
@Test
public void test_commitAndRollback() {
Transaction txn = Ebean.beginTransaction();
Ebean.register(new MyCallback());
txn.getConnection();
Ebean.commitTransaction();
assertEquals(1, countPreCommit);
assertEquals(1, countPostCommit);
assertEquals(0, countPreRollback);
assertEquals(0, countPostRollback);
Ebean.beginTransaction();
Ebean.register(new MyCallback());
Ebean.rollbackTransaction();
assertEquals(1, countPreCommit);
assertEquals(1, countPostCommit);
assertEquals(1, countPreRollback);
assertEquals(1, countPostRollback);
}
@Test(expected = PersistenceException.class)
public void test_withEbeanserver() {
EbeanServer server = Ebean.getServer(null);
server.register(new MyCallback());
}
class MyCallback extends TransactionCallbackAdapter {
@Override
public void preCommit() {
countPreCommit++;
}
@Override
public void postCommit() {
countPostCommit++;
}
@Override
public void preRollback() {
countPreRollback++;
}
@Override
public void postRollback() {
countPostRollback++;
}
}
}
@@ -0,0 +1,58 @@
package org.tests.transaction;
import io.ebean.Ebean;
import io.ebean.Transaction;
import io.ebean.annotation.Transactional;
import org.tests.model.basic.EBasic;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class TestTransactionRollbackOnly {
private EBasic one;
private EBasic two;
@Test
public void transaction_setRollbackOnly() {
doVia_currentTransaction();
assertThat(one.getId()).isNotNull();
assertThat(Ebean.find(EBasic.class, one.getId())).isNull();
}
@Transactional
protected void doVia_currentTransaction() {
one = new EBasic("WillNotSave");
Ebean.save(one);
Transaction transaction = Ebean.currentTransaction();
assertFalse(transaction.isRollbackOnly());
transaction.setRollbackOnly();
assertTrue(transaction.isRollbackOnly());
}
@Test
public void test_Ebean_setRollbackOnly() {
do_Ebean_setRollbackOnly();
assertThat(two.getId()).isNotNull();
assertThat(Ebean.find(EBasic.class, two.getId())).isNull();
}
@Transactional
protected void do_Ebean_setRollbackOnly() {
two = new EBasic("WillNotSave");
Ebean.save(two);
Ebean.setRollbackOnly();
}
}
@@ -0,0 +1,79 @@
package org.tests.transaction;
import io.ebean.Ebean;
import io.ebean.annotation.Transactional;
import org.avaje.agentloader.AgentLoader;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PersistenceException;
import javax.persistence.Table;
import java.util.List;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* It shows the issue that the user record does NOT rolback when there is an exception thrown
*/
public class TransactionNotTerminatedAfterRollback {
private static final Logger LOG = LoggerFactory.getLogger(TransactionNotTerminatedAfterRollback.class);
@BeforeClass
public static void preStart() {
LOG.debug("... preStart");
// display the log message to see if the UserService is enhanced
AgentLoader.loadAgentFromClasspath("avaje-ebeanorm-agent", "debug=1");
}
@Test
public void test() {
try {
new UserService().create(new User(1L, "David"));
fail("Exception should be thrown");
} catch (PersistenceException pe) {
LOG.error("e: " + pe);
}
List<User> users = Ebean.find(User.class).findList();
LOG.debug("users: {}", users);
assertTrue("users should be empty", users.isEmpty());
}
@Transactional(rollbackFor = PersistenceException.class)
public class UserService {
public void create(User i) {
Ebean.save(i);
Ebean.save(new User(1L, "Peter")); // make it throw exception and rollback
}
}
@Entity
@Table(name = "tx_user")
public static class User {
@Id
Long id;
String name;
public User() {
}
public User(Long id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append("{");
s.append("id: ").append(id).append(", ");
s.append("name: ").append(name);
s.append("}");
return s.toString();
}
}
}