mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#203: ENH: Add Transaction hook ... for preCommit(), postCommit(), postRollback()
This commit is contained in:
@@ -281,7 +281,7 @@ public final class Ebean {
|
||||
* Register the server with this Ebean singleton. Specify if the registered
|
||||
* server is the primary/default server.
|
||||
*/
|
||||
protected static void register(EbeanServer server, boolean isPrimaryServer) {
|
||||
public static void register(EbeanServer server, boolean isPrimaryServer) {
|
||||
serverMgr.register(server, isPrimaryServer);
|
||||
}
|
||||
|
||||
@@ -372,6 +372,19 @@ public final class Ebean {
|
||||
return serverMgr.getPrimaryServer().currentTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback on the currently active transaction.
|
||||
* <p/>
|
||||
* If there is no currently active transaction then a PersistenceException is thrown.
|
||||
*
|
||||
* @param transactionCallback The transaction callback to be registered with the current transaction.
|
||||
*
|
||||
* @throws PersistenceException If there is no currently active transaction
|
||||
*/
|
||||
public static void register(TransactionCallback transactionCallback) throws PersistenceException {
|
||||
serverMgr.getPrimaryServer().register(transactionCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheStrategy;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
@@ -307,6 +308,17 @@ public interface EbeanServer {
|
||||
*/
|
||||
public SqlUpdate createNamedSqlUpdate(String namedQuery);
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback on the currently active transaction.
|
||||
* <p/>
|
||||
* If there is no currently active transaction then a PersistenceException is thrown.
|
||||
*
|
||||
* @param transactionCallback The transaction callback to be registered with the current transaction.
|
||||
*
|
||||
* @throws PersistenceException If there is no currently active transaction
|
||||
*/
|
||||
public void register(TransactionCallback transactionCallback) throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Create a new transaction that is not held in TransactionThreadLocal.
|
||||
* <p>
|
||||
|
||||
@@ -35,6 +35,11 @@ public interface Transaction extends Closeable {
|
||||
*/
|
||||
public static final int SERIALIZABLE = java.sql.Connection.TRANSACTION_SERIALIZABLE;
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback with this transaction.
|
||||
*/
|
||||
public void register(TransactionCallback callback);
|
||||
|
||||
/**
|
||||
* Return true if this transaction is read only.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Provides a callback that can be registered with a Transaction.
|
||||
* <p/>
|
||||
* The callback methods are called just prior to and after the transaction performs a commit or rollback.
|
||||
* <p/>
|
||||
* A typical use of TransactionCallback would be to clean up non-transactional resources like files. For example,
|
||||
* when processing files on postCommit/postRollback clean up the associated files. As another example when
|
||||
* on postCommit of a delete remove associated resources from the file system or remote service.
|
||||
*/
|
||||
public interface TransactionCallback {
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction commit.
|
||||
*/
|
||||
void preCommit();
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction commit.
|
||||
*/
|
||||
void postCommit();
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction rollback.
|
||||
*/
|
||||
void preRollback();
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction rollback.
|
||||
*/
|
||||
void postRollback();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Adapter that can be extended for easier implementation of TransactionCallback.
|
||||
* <p/>
|
||||
* Provides 'no operation' implementation for each of the TransactionCallback methods. It is expected that this
|
||||
* class is extended and override the methods you need to.
|
||||
*/
|
||||
public abstract class TransactionCallbackAdapter implements TransactionCallback {
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction commit.
|
||||
*/
|
||||
@Override
|
||||
public void preCommit() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction commit.
|
||||
*/
|
||||
@Override
|
||||
public void postCommit() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction rollback.
|
||||
*/
|
||||
@Override
|
||||
public void preRollback() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction rollback.
|
||||
*/
|
||||
@Override
|
||||
public void postRollback() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
}
|
||||
@@ -19,179 +19,179 @@ public interface SpiTransaction extends Transaction {
|
||||
* End the transaction when had query only use.
|
||||
*/
|
||||
public void endQueryOnly();
|
||||
|
||||
|
||||
/**
|
||||
* Return the string prefix with the transactin id and label used in logging.
|
||||
*/
|
||||
public String getLogPrefix();
|
||||
|
||||
/**
|
||||
* Return true if generated SQL and Bind values should be logged to the
|
||||
* transaction log.
|
||||
*/
|
||||
public boolean isLogSql();
|
||||
|
||||
/**
|
||||
* Return true if summary level events should be logged to the transaction
|
||||
* log.
|
||||
*/
|
||||
public boolean isLogSummary();
|
||||
/**
|
||||
* Return true if generated SQL and Bind values should be logged to the
|
||||
* transaction log.
|
||||
*/
|
||||
public boolean isLogSql();
|
||||
|
||||
/**
|
||||
* Log a message to the SQL logger.
|
||||
*/
|
||||
public void logSql(String msg);
|
||||
/**
|
||||
* Return true if summary level events should be logged to the transaction
|
||||
* log.
|
||||
*/
|
||||
public boolean isLogSummary();
|
||||
|
||||
/**
|
||||
* Log a message to the SUMMARY logger.
|
||||
*/
|
||||
public void logSummary(String msg);
|
||||
/**
|
||||
* Log a message to the SQL logger.
|
||||
*/
|
||||
public void logSql(String msg);
|
||||
|
||||
/**
|
||||
* Register a "Derived Relationship" (that requires an additional update).
|
||||
*/
|
||||
public void registerDerivedRelationship(DerivedRelationshipData assocBean);
|
||||
/**
|
||||
* Log a message to the SUMMARY logger.
|
||||
*/
|
||||
public void logSummary(String msg);
|
||||
|
||||
/**
|
||||
* Return the list of "Derived Relationships" that must be maintained after
|
||||
* insert.
|
||||
*/
|
||||
public List<DerivedRelationshipData> getDerivedRelationship(Object bean);
|
||||
/**
|
||||
* Register a "Derived Relationship" (that requires an additional update).
|
||||
*/
|
||||
public void registerDerivedRelationship(DerivedRelationshipData assocBean);
|
||||
|
||||
/**
|
||||
* Add a deleting bean to the registered list.
|
||||
* <p>
|
||||
* This is to handle bi-directional relationships where both sides Cascade.
|
||||
* </p>
|
||||
*/
|
||||
public void registerDeleteBean(Integer hash);
|
||||
/**
|
||||
* Return the list of "Derived Relationships" that must be maintained after
|
||||
* insert.
|
||||
*/
|
||||
public List<DerivedRelationshipData> getDerivedRelationship(Object bean);
|
||||
|
||||
/**
|
||||
* Unregister the hash of the bean.
|
||||
*/
|
||||
public void unregisterDeleteBean(Integer hash);
|
||||
/**
|
||||
* Add a deleting bean to the registered list.
|
||||
* <p>
|
||||
* This is to handle bi-directional relationships where both sides Cascade.
|
||||
* </p>
|
||||
*/
|
||||
public void registerDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been saved/deleted.
|
||||
*/
|
||||
public boolean isRegisteredDeleteBean(Integer hash);
|
||||
/**
|
||||
* Unregister the hash of the bean.
|
||||
*/
|
||||
public void unregisterDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Unregister the persisted bean.
|
||||
*/
|
||||
public void unregisterBean(Object bean);
|
||||
/**
|
||||
* Return true if this is a bean that has already been saved/deleted.
|
||||
*/
|
||||
public boolean isRegisteredDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been persisted in the
|
||||
* current recursive save request. The goal is to stop recursively saving
|
||||
* the bean when cascade persist is on both sides of a relationship).
|
||||
* <p>
|
||||
* This will register the bean if it is not already.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isRegisteredBean(Object bean);
|
||||
/**
|
||||
* Unregister the persisted bean.
|
||||
*/
|
||||
public void unregisterBean(Object bean);
|
||||
|
||||
/**
|
||||
* Returns a String used to identify the transaction. This id is used for
|
||||
* Transaction logging.
|
||||
*/
|
||||
public String getId();
|
||||
/**
|
||||
* Return true if this is a bean that has already been persisted in the
|
||||
* current recursive save request. The goal is to stop recursively saving
|
||||
* the bean when cascade persist is on both sides of a relationship).
|
||||
* <p>
|
||||
* This will register the bean if it is not already.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isRegisteredBean(Object bean);
|
||||
|
||||
/**
|
||||
* Return the batchSize specifically set for this transaction or 0.
|
||||
* <p>
|
||||
* Returning 0 implies to use the system wide default batch size.
|
||||
* </p>
|
||||
*/
|
||||
public int getBatchSize();
|
||||
/**
|
||||
* Returns a String used to identify the transaction. This id is used for
|
||||
* Transaction logging.
|
||||
*/
|
||||
public String getId();
|
||||
|
||||
/**
|
||||
* Modify and return the current 'depth' of the transaction.
|
||||
* <p>
|
||||
* As we cascade save or delete we traverse the object graph tree. Going up
|
||||
* to Assoc Ones the depth decreases and going down to Assoc Manys the depth
|
||||
* increases.
|
||||
* </p>
|
||||
* <p>
|
||||
* The depth is used for ordering batching statements. The lowest depth get
|
||||
* executed first during save.
|
||||
* </p>
|
||||
*/
|
||||
public int depth(int diff);
|
||||
/**
|
||||
* Return the batchSize specifically set for this transaction or 0.
|
||||
* <p>
|
||||
* Returning 0 implies to use the system wide default batch size.
|
||||
* </p>
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
/**
|
||||
* Return true if this transaction was created explicitly via
|
||||
* <code>Ebean.beginTransaction()</code>.
|
||||
*/
|
||||
public boolean isExplicit();
|
||||
/**
|
||||
* Modify and return the current 'depth' of the transaction.
|
||||
* <p>
|
||||
* As we cascade save or delete we traverse the object graph tree. Going up
|
||||
* to Assoc Ones the depth decreases and going down to Assoc Manys the depth
|
||||
* increases.
|
||||
* </p>
|
||||
* <p>
|
||||
* The depth is used for ordering batching statements. The lowest depth get
|
||||
* executed first during save.
|
||||
* </p>
|
||||
*/
|
||||
public int depth(int diff);
|
||||
|
||||
/**
|
||||
* Get the object that holds the event details.
|
||||
* <p>
|
||||
* This information is used maintain the table state, cache and text
|
||||
* indexes. On commit the Table modifications this generates is broadcast
|
||||
* around the cluster (if you have a cluster).
|
||||
* </p>
|
||||
*/
|
||||
public TransactionEvent getEvent();
|
||||
/**
|
||||
* Return true if this transaction was created explicitly via
|
||||
* <code>Ebean.beginTransaction()</code>.
|
||||
*/
|
||||
public boolean isExplicit();
|
||||
|
||||
/**
|
||||
* Whether persistCascade is on for save and delete.
|
||||
*/
|
||||
public boolean isPersistCascade();
|
||||
/**
|
||||
* Get the object that holds the event details.
|
||||
* <p>
|
||||
* This information is used maintain the table state, cache and text
|
||||
* indexes. On commit the Table modifications this generates is broadcast
|
||||
* around the cluster (if you have a cluster).
|
||||
* </p>
|
||||
*/
|
||||
public TransactionEvent getEvent();
|
||||
|
||||
/**
|
||||
* Return true if this request should be batched. Conversely returns false
|
||||
* if this request should be executed immediately.
|
||||
*/
|
||||
public boolean isBatchThisRequest();
|
||||
/**
|
||||
* Whether persistCascade is on for save and delete.
|
||||
*/
|
||||
public boolean isPersistCascade();
|
||||
|
||||
/**
|
||||
* Return the queue used to batch up persist requests.
|
||||
*/
|
||||
public BatchControl getBatchControl();
|
||||
/**
|
||||
* Return true if this request should be batched. Conversely returns false
|
||||
* if this request should be executed immediately.
|
||||
*/
|
||||
public boolean isBatchThisRequest();
|
||||
|
||||
/**
|
||||
* Set the queue used to batch up persist requests. There should only be one
|
||||
* PersistQueue set per transaction.
|
||||
*/
|
||||
public void setBatchControl(BatchControl control);
|
||||
/**
|
||||
* Return the queue used to batch up persist requests.
|
||||
*/
|
||||
public BatchControl getBatchControl();
|
||||
|
||||
/**
|
||||
* Return the persistence context associated with this transaction.
|
||||
* <p>
|
||||
* You may wish to hold onto this and set it against another transaction
|
||||
* later. This is along the lines of 'extended persistence context'
|
||||
* behaviour.
|
||||
* </p>
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
/**
|
||||
* Set the queue used to batch up persist requests. There should only be one
|
||||
* PersistQueue set per transaction.
|
||||
*/
|
||||
public void setBatchControl(BatchControl control);
|
||||
|
||||
/**
|
||||
* Set the persistence context to this transaction.
|
||||
* <p>
|
||||
* This could be considered similar to 'EJB3 Extended Persistence Context'.
|
||||
* In that you can get the PersistenceContext from a transaction, hold onto
|
||||
* it, and then set it back later to a second transaction. In general there
|
||||
* is one PersistenceContext per Transaction. The getPersistenceContext()
|
||||
* and setPersistenceContext() enable a developer to reuse a single
|
||||
* PersistenceContext with multiple transactions.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersistenceContext(PersistenceContext context);
|
||||
/**
|
||||
* Return the persistence context associated with this transaction.
|
||||
* <p>
|
||||
* You may wish to hold onto this and set it against another transaction
|
||||
* later. This is along the lines of 'extended persistence context'
|
||||
* behaviour.
|
||||
* </p>
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Return the underlying Connection for internal use.
|
||||
* <p>
|
||||
* If the connection is made public from Transaction and the user code calls
|
||||
* that method we can no longer trust the query only status of a
|
||||
* Transaction.
|
||||
* </p>
|
||||
*/
|
||||
public Connection getInternalConnection();
|
||||
/**
|
||||
* Set the persistence context to this transaction.
|
||||
* <p>
|
||||
* This could be considered similar to 'EJB3 Extended Persistence Context'.
|
||||
* In that you can get the PersistenceContext from a transaction, hold onto
|
||||
* it, and then set it back later to a second transaction. In general there
|
||||
* is one PersistenceContext per Transaction. The getPersistenceContext()
|
||||
* and setPersistenceContext() enable a developer to reuse a single
|
||||
* PersistenceContext with multiple transactions.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersistenceContext(PersistenceContext context);
|
||||
|
||||
/**
|
||||
* Return true if the manyToMany intersection should be persisted for this particular relationship direction.
|
||||
*/
|
||||
/**
|
||||
* Return the underlying Connection for internal use.
|
||||
* <p>
|
||||
* If the connection is made public from Transaction and the user code calls
|
||||
* that method we can no longer trust the query only status of a
|
||||
* Transaction.
|
||||
* </p>
|
||||
*/
|
||||
public Connection getInternalConnection();
|
||||
|
||||
/**
|
||||
* Return true if the manyToMany intersection should be persisted for this particular relationship direction.
|
||||
*/
|
||||
public boolean isSaveAssocManyIntersection(String intersectionTable, String beanName);
|
||||
}
|
||||
|
||||
@@ -653,6 +653,15 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
return (T) ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(TransactionCallback transactionCallback) {
|
||||
Transaction transaction = currentTransaction();
|
||||
if (transaction == null) {
|
||||
throw new PersistenceException("Not currently active transaction when trying to register transactionCallback");
|
||||
}
|
||||
transaction.register(transactionCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Transaction that is NOT stored in TransactionThreadLocal. Use
|
||||
* this when you want a thread to have a second independent transaction.
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.Map;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.RollbackException;
|
||||
|
||||
import com.avaje.ebean.TransactionCallback;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -129,6 +130,8 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
|
||||
protected Map<String, Object> userObjects;
|
||||
|
||||
protected List<TransactionCallback> callbackList;
|
||||
|
||||
/**
|
||||
* Create a new JdbcTransaction.
|
||||
*/
|
||||
@@ -171,6 +174,63 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
return logPrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(TransactionCallback callback) {
|
||||
if (callbackList == null) {
|
||||
callbackList = new ArrayList<TransactionCallback>(4);
|
||||
}
|
||||
callbackList.add(callback);
|
||||
}
|
||||
|
||||
protected void firePreRollback() {
|
||||
if (callbackList != null) {
|
||||
for (TransactionCallback callback : callbackList) {
|
||||
try {
|
||||
callback.preRollback();
|
||||
} catch (Exception e) {
|
||||
logger.error("Error executing preRollback callback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void firePostRollback() {
|
||||
if (callbackList != null) {
|
||||
for (TransactionCallback callback : callbackList) {
|
||||
try {
|
||||
callback.postRollback();
|
||||
} catch (Exception e) {
|
||||
logger.error("Error executing postRollback callback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void firePreCommit() {
|
||||
if (callbackList != null) {
|
||||
for (TransactionCallback callback : callbackList) {
|
||||
try {
|
||||
callback.preCommit();
|
||||
} catch (Exception e) {
|
||||
logger.error("Error executing preCommit callback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void firePostCommit() {
|
||||
if (callbackList != null) {
|
||||
for (TransactionCallback callback : callbackList) {
|
||||
try {
|
||||
callback.postCommit();
|
||||
} catch (Exception e) {
|
||||
logger.error("Error executing postCommit callback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<DerivedRelationshipData> getDerivedRelationship(Object bean) {
|
||||
if (derivedRelMap == null) {
|
||||
return null;
|
||||
@@ -603,6 +663,9 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
if (!isActive()) {
|
||||
throw new IllegalStateException(illegalStateMessage);
|
||||
}
|
||||
|
||||
firePreCommit();
|
||||
|
||||
try {
|
||||
if (queryOnly) {
|
||||
// can rollback or just close for performance
|
||||
@@ -620,6 +683,7 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
|
||||
} finally {
|
||||
// these will not throw an exception
|
||||
firePostCommit();
|
||||
deactivate();
|
||||
notifyCommit();
|
||||
}
|
||||
@@ -653,6 +717,7 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
if (!isActive()) {
|
||||
throw new IllegalStateException(illegalStateMessage);
|
||||
}
|
||||
firePreRollback();
|
||||
try {
|
||||
performRollback();
|
||||
|
||||
@@ -661,6 +726,7 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
|
||||
} finally {
|
||||
// these will not throw an exception
|
||||
firePostRollback();
|
||||
deactivate();
|
||||
notifyRollback(cause);
|
||||
}
|
||||
|
||||
@@ -427,10 +427,9 @@ public class TransactionManager {
|
||||
for (TransactionEventListener listener : transactionEventListeners) {
|
||||
listener.postTransactionCommit(transaction);
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
String m = "NotifyOfCommit failed. L2 Cache potentially not notified.";
|
||||
logger.error(m, ex);
|
||||
|
||||
} catch (Exception ex) {
|
||||
logger.error("NotifyOfCommit failed. L2 Cache potentially not notified.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.avaje.tests.transaction;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.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() {
|
||||
|
||||
|
||||
Ebean.beginTransaction();
|
||||
Ebean.register(new MyCallback());
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user