mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Typically useful for handling DuplicateKeyException where we expect DuplicateKeyException to be thrown and catch it with the intention of continuing processing using the same transaction. Note that some databases like Oracle do not require this explicit rollback() and would work without the rollbackAndContinue(). Postgres in particular requires the rollback() call on the underlying connection such that we can continue using that transaction/java.sql.Connection. Note that in the existing test we can see that rollbackAndContinue() is pretty close to being syntactic sugar. I think adding rollbackAndContinue() is justified and complements the existing commitAndContinue().
104 lines
3.0 KiB
Java
104 lines
3.0 KiB
Java
package org.tests.insert;
|
|
|
|
import io.ebean.DB;
|
|
import io.ebean.DuplicateKeyException;
|
|
import io.ebean.annotation.Transactional;
|
|
import io.ebean.xtest.BaseTestCase;
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.tests.model.draftable.Document;
|
|
|
|
import java.util.List;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
|
|
public class TestInsertDuplicateKey extends BaseTestCase {
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(TestInsertDuplicateKey.class);
|
|
|
|
@BeforeEach
|
|
public void clearDb() {
|
|
server().find(Document.class).asDraft().where().contains("title", "UniqueKey").delete();
|
|
}
|
|
|
|
@Test
|
|
public void insert_duplicateKey() {
|
|
Document doc1 = new Document();
|
|
doc1.setTitle("ThisIsAUniqueKey");
|
|
doc1.setBody("one");
|
|
doc1.save();
|
|
|
|
assertThrows(DuplicateKeyException.class, () -> {
|
|
Document doc2 = new Document();
|
|
doc2.setTitle("ThisIsAUniqueKey");
|
|
doc2.setBody("clashes with doc1");
|
|
doc2.save();
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void insertBatch_duplicateKey() {
|
|
assertThrows(DuplicateKeyException.class, this::insertBatch_duplicateKey_action);
|
|
}
|
|
|
|
@Transactional(batchSize = 100)
|
|
void insertBatch_duplicateKey_action() {
|
|
Document doc1 = new Document();
|
|
doc1.setTitle("ThisIsASecondUniqueKey");
|
|
doc1.setBody("one");
|
|
doc1.save();
|
|
|
|
Document doc2 = new Document();
|
|
doc2.setTitle("ThisIsASecondUniqueKey");
|
|
doc2.setBody("clash when batch flushed");
|
|
doc2.save();
|
|
}
|
|
|
|
@Test
|
|
public void insertBatch_duplicateKey_catchAndContinue() {
|
|
|
|
insertTheBatch_duplicateKey_catchAndContinue();
|
|
|
|
List<Document> found = DB.getDefault()
|
|
.find(Document.class)
|
|
.asDraft()
|
|
.where().startsWith("body", "insertTheBatch_duplicateKey_catchAndContinue")
|
|
.findList();
|
|
|
|
assertThat(found).hasSize(1);
|
|
assertThat(found.get(0).getTitle()).isEqualTo("ThisIsAThirdUniqueKey");
|
|
assertThat(found.get(0).getBody()).isEqualTo("insertTheBatch_duplicateKey_catchAndContinue-1");
|
|
}
|
|
|
|
@Transactional//(batchSize = 100)
|
|
private void insertTheBatch_duplicateKey_catchAndContinue() {
|
|
|
|
Document doc1 = new Document();
|
|
doc1.setTitle("ThisIsAThirdUniqueKey");
|
|
doc1.setBody("insertTheBatch_duplicateKey_catchAndContinue-1");
|
|
doc1.save();
|
|
|
|
try {
|
|
Document doc2 = new Document();
|
|
doc2.setTitle("ThisIsAThirdUniqueKey");
|
|
doc2.setBody("insertTheBatch_duplicateKey_catchAndContinue-2");
|
|
doc2.save();
|
|
|
|
// flush at this point, fails
|
|
DB.getDefault().currentTransaction().flush();
|
|
} catch (DuplicateKeyException e) {
|
|
log.info("duplicate failed but just continue" + e.getMessage());
|
|
// rollback and continue using the transaction
|
|
DB.getDefault().currentTransaction().rollbackAndContinue();
|
|
}
|
|
|
|
Document doc0 = new Document();
|
|
doc0.setTitle("ThisIsAThirdUniqueKey");
|
|
doc0.setBody("insertTheBatch_duplicateKey_catchAndContinue-1");
|
|
doc0.save();
|
|
}
|
|
}
|