mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Added @Transactional support for PersistBatch #220
This commit is contained in:
@@ -106,7 +106,7 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-agent</artifactId>
|
||||
<version>4.1.10</version>
|
||||
<version>4.5.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
<plugin>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
|
||||
<version>4.1.9</version>
|
||||
<version>4.5.1</version>
|
||||
<executions>
|
||||
<!-- Not going to enhance Model bean -->
|
||||
<execution>
|
||||
|
||||
@@ -212,6 +212,11 @@ public interface Transaction extends Closeable {
|
||||
*/
|
||||
public void setBatchSize(int batchSize);
|
||||
|
||||
/**
|
||||
* Return the current batch size.
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
/**
|
||||
* Specify if you want batched inserts to use getGeneratedKeys.
|
||||
* <p>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
@@ -28,12 +30,39 @@ public final class TxScope {
|
||||
|
||||
TxIsolation isolation;
|
||||
|
||||
PersistBatch batch;
|
||||
|
||||
PersistBatch batchOnCascade;
|
||||
|
||||
int batchSize;
|
||||
|
||||
boolean readOnly;
|
||||
|
||||
ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
|
||||
ArrayList<Class<? extends Throwable>> noRollbackFor;
|
||||
|
||||
/**
|
||||
* Return true if PersistBatch has been set.
|
||||
*/
|
||||
public boolean isBatchSet() {
|
||||
return batch != null && batch != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch on cascade has been set.
|
||||
*/
|
||||
public boolean isBatchOnCascadeSet() {
|
||||
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch size has been set.
|
||||
*/
|
||||
public boolean isBatchSizeSet() {
|
||||
return batchSize > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with REQUIRES.
|
||||
*/
|
||||
@@ -114,6 +143,51 @@ public final class TxScope {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch mode.
|
||||
*/
|
||||
public PersistBatch getBatch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch mode to use.
|
||||
*/
|
||||
public TxScope setBatch(PersistBatch batch) {
|
||||
this.batch = batch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch on cascade mode.
|
||||
*/
|
||||
public PersistBatch getBatchOnCascade() {
|
||||
return batchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch on cascade mode.
|
||||
*/
|
||||
public TxScope setBatchOnCascade(PersistBatch batchOnCascade) {
|
||||
this.batchOnCascade = batchOnCascade;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size. 0 means use the default value.
|
||||
*/
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch size to use.
|
||||
*/
|
||||
public TxScope setBatchSize(int batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the transaction should be treated as read only.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.TxIsolation;
|
||||
import com.avaje.ebean.TxType;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
/**
|
||||
* Specify transaction scoping for a method.
|
||||
@@ -66,6 +67,29 @@ public @interface Transactional {
|
||||
*/
|
||||
TxType type() default TxType.REQUIRED;
|
||||
|
||||
/**
|
||||
* Persist batch mode for the transaction.
|
||||
*/
|
||||
PersistBatch batch() default PersistBatch.INHERIT;
|
||||
|
||||
/**
|
||||
* Persist batch mode for the request if not set on the transaction.
|
||||
* <p>
|
||||
* If batch is set to NONE then batchOnCascade can be set to INSERT or ALL
|
||||
* and then each save(), delete(), insert(), update() request that cascades
|
||||
* to child beans can use JDBC batch.
|
||||
* </p>
|
||||
*/
|
||||
PersistBatch batchOnCascade() default PersistBatch.INHERIT;
|
||||
|
||||
/**
|
||||
* The batch size to use when using JDBC batch mode.
|
||||
* <p>
|
||||
* If unset this defaults to the value set in ServerConfig.
|
||||
* </p>
|
||||
*/
|
||||
int batchSize() default 0;
|
||||
|
||||
/**
|
||||
* The transaction isolation level this transaction should have.
|
||||
* <p>
|
||||
|
||||
@@ -27,7 +27,14 @@ public enum PersistBatch {
|
||||
/**
|
||||
* Use JDBC Batch mode on Inserts, Updates and Deletes.
|
||||
*/
|
||||
ALL(true);
|
||||
ALL(true),
|
||||
|
||||
/**
|
||||
* You should not use this value explicitly. It should only used on the Transactional annotation
|
||||
* to indicate that the value should inherit from the ServerConfig setting.
|
||||
*/
|
||||
INHERIT(false);
|
||||
|
||||
|
||||
boolean forInsert;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.api;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.avaje.ebean.TxScope;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
/**
|
||||
* Used internally to handle the scoping of transactions for methods.
|
||||
@@ -10,14 +11,14 @@ import com.avaje.ebean.TxScope;
|
||||
public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
private static final int OPCODE_ATHROW = 191;
|
||||
//private static final int OPCODE_ATHROW = com.avaje.ebean.enhance.asm.Opcodes.ATHROW;
|
||||
|
||||
|
||||
private final SpiTransactionScopeManager scopeMgr;
|
||||
|
||||
/**
|
||||
* The suspended transaction (can be null).
|
||||
*/
|
||||
private final SpiTransaction suspendedTransaction;
|
||||
|
||||
/**
|
||||
* The transaction in scope (can be null).
|
||||
*/
|
||||
@@ -44,7 +45,13 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
*/
|
||||
private final ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
|
||||
/**
|
||||
private PersistBatch restoreBatch;
|
||||
|
||||
private PersistBatch restoreBatchOnCascade;
|
||||
|
||||
private int restoreBatchSize;
|
||||
|
||||
/**
|
||||
* Flag set when a rollback has occurred.
|
||||
*/
|
||||
private boolean rolledBack;
|
||||
@@ -61,6 +68,24 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
this.noRollbackFor = txScope.getNoRollbackFor();
|
||||
this.rollbackFor = txScope.getRollbackFor();
|
||||
|
||||
if (transaction != null) {
|
||||
if (!created && txScope.isBatchSet() || txScope.isBatchOnCascadeSet() || txScope.isBatchSizeSet()) {
|
||||
restoreBatch = transaction.getBatch();
|
||||
restoreBatchOnCascade = transaction.getBatchOnCascade();
|
||||
restoreBatchSize = transaction.getBatchSize();
|
||||
}
|
||||
if (txScope.isBatchSet()) {
|
||||
transaction.setBatch(txScope.getBatch());
|
||||
}
|
||||
if (txScope.isBatchOnCascadeSet()) {
|
||||
transaction.setBatchOnCascade(txScope.getBatchOnCascade());
|
||||
}
|
||||
if (txScope.isBatchSizeSet()) {
|
||||
transaction.setBatchSize(txScope.getBatchSize());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,10 +122,22 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
*/
|
||||
public void onFinally() {
|
||||
try {
|
||||
if (!rolledBack && created) {
|
||||
transaction.commit();
|
||||
if (!rolledBack) {
|
||||
if (created) {
|
||||
transaction.commit();
|
||||
} else {
|
||||
if (restoreBatch != null) {
|
||||
transaction.setBatch(restoreBatch);
|
||||
}
|
||||
if (restoreBatchOnCascade != null) {
|
||||
transaction.setBatchOnCascade(restoreBatchOnCascade);
|
||||
}
|
||||
if (restoreBatchSize > 0) {
|
||||
transaction.setBatchSize(restoreBatchSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} finally {
|
||||
if (suspendedTransaction != null){
|
||||
// put the previously suspended transaction
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.tests.batchinsert;
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.annotation.Transactional;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
import com.avaje.tests.model.basic.UTDetail;
|
||||
import com.avaje.tests.model.basic.UTMaster;
|
||||
@@ -29,7 +30,7 @@ public class TestBatchInsertSimple extends BaseTestCase {
|
||||
|
||||
for (int i = 0; i < numOfMasters; i++) {
|
||||
UTMaster master = createMasterAndDetails(i, 20);
|
||||
Ebean.save(master);
|
||||
master.save();
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
@@ -39,6 +40,24 @@ public class TestBatchInsertSimple extends BaseTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactional() {
|
||||
|
||||
saveWithFullBatchMode();
|
||||
}
|
||||
|
||||
@Transactional(batch=PersistBatch.ALL, batchSize=50)
|
||||
public void saveWithFullBatchMode() {
|
||||
|
||||
int numOfMasters = 4;
|
||||
|
||||
for (int i = 0; i < numOfMasters; i++) {
|
||||
UTMaster master = createMasterAndDetails(i, 5);
|
||||
// the save is 'batched' and does not execute immediately
|
||||
// ... it now acts more like 'merge/persist'
|
||||
master.save();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJdbcBatchPerRequestWithMasterOnly() {
|
||||
@@ -132,8 +151,8 @@ public class TestBatchInsertSimple extends BaseTestCase {
|
||||
|
||||
UTDetail detail = new UTDetail();
|
||||
detail.setName("batchInsert-detail-" + position);
|
||||
detail.setQty(Integer.valueOf(qty));
|
||||
detail.setAmount(Double.valueOf(amount));
|
||||
detail.setQty(qty);
|
||||
detail.setAmount(amount);
|
||||
|
||||
// System.out.println("-- "+detail);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.tests.model.basic;
|
||||
|
||||
import com.avaje.ebean.Model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -12,7 +14,7 @@ import javax.persistence.Version;
|
||||
|
||||
@Entity
|
||||
@Table(name="ut_master")
|
||||
public class UTMaster {
|
||||
public class UTMaster extends Model {
|
||||
|
||||
@Id
|
||||
Integer id;
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -12,6 +13,8 @@ import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.TxType;
|
||||
import com.avaje.ebean.annotation.Transactional;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class DummyDao {
|
||||
|
||||
Logger logger = LoggerFactory.getLogger(DummyDao.class);
|
||||
@@ -33,5 +36,34 @@ public class DummyDao {
|
||||
public void addToObject(Long id, Double anotherNumber, List<Long> ids) throws EntityNotFoundException {
|
||||
// and more code
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Transactional(batch = PersistBatch.ALL, batchOnCascade = PersistBatch.ALL, batchSize = 99)
|
||||
public void doWithBatchOptionsSet() {
|
||||
|
||||
Transaction txn = Ebean.currentTransaction();
|
||||
assertEquals(PersistBatch.ALL, txn.getBatch());
|
||||
assertEquals(PersistBatch.ALL, txn.getBatchOnCascade());
|
||||
assertEquals(99, txn.getBatchSize());
|
||||
}
|
||||
|
||||
|
||||
@Transactional(batch = PersistBatch.INSERT, batchOnCascade = PersistBatch.NONE, batchSize = 77)
|
||||
public void doOuterWithBatchOptionsSet() {
|
||||
|
||||
Transaction txn = Ebean.currentTransaction();
|
||||
|
||||
assertEquals(PersistBatch.INSERT, txn.getBatch());
|
||||
assertEquals(PersistBatch.NONE, txn.getBatchOnCascade());
|
||||
assertEquals(77, txn.getBatchSize());
|
||||
|
||||
doWithBatchOptionsSet();
|
||||
|
||||
// batch options set back
|
||||
assertEquals(PersistBatch.INSERT, txn.getBatch());
|
||||
assertEquals(PersistBatch.NONE, txn.getBatchOnCascade());
|
||||
assertEquals(77, txn.getBatchSize());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,15 @@ public class TestTxTypeOnTransactional extends BaseTestCase {
|
||||
|
||||
Logger logger = LoggerFactory.getLogger(TestTxTypeOnTransactional.class);
|
||||
|
||||
@Test
|
||||
public void testBatchOptionsAreSet() {
|
||||
|
||||
logger.info("-- test pre doOuterWithBatchOptionsSet");
|
||||
DummyDao dao = new DummyDao();
|
||||
dao.doOuterWithBatchOptionsSet();
|
||||
logger.info("-- test post doOuterWithBatchOptionsSet");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user