mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#991 ENH: Add forUpdateNoWait() and forUpdateSkipLocked() options ... #528 ENH: Improve exception handling
This commit is contained in:
@@ -1,46 +0,0 @@
|
||||
package org.tests.basic;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Query;
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestQuery extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void testCountOrderBy() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class).setAutoTune(false).order().asc("orderDate")
|
||||
.order().desc("id");
|
||||
// .orderBy("orderDate");
|
||||
|
||||
int rc = query.findList().size();
|
||||
Assert.assertTrue(rc > 0);
|
||||
// String generatedSql = query.getGeneratedSql();
|
||||
// Assert.assertFalse(generatedSql.contains("order by"));
|
||||
|
||||
}
|
||||
|
||||
public void testForUpdate() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class).setAutoTune(false).setForUpdate(false)
|
||||
.setMaxRows(1).order().asc("orderDate").order().desc("id");
|
||||
|
||||
int rc = query.findList().size();
|
||||
Assert.assertTrue(rc > 0);
|
||||
Assert.assertTrue(!query.getGeneratedSql().toLowerCase().contains("for update"));
|
||||
|
||||
query = Ebean.find(Order.class).setAutoTune(false).setForUpdate(true).setMaxRows(1).order()
|
||||
.asc("orderDate").order().desc("id");
|
||||
|
||||
rc = query.findList().size();
|
||||
Assert.assertTrue(rc > 0);
|
||||
Assert.assertTrue(query.getGeneratedSql().toLowerCase().contains("for update"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package org.tests.basic;
|
||||
|
||||
import io.ebean.AcquireLockException;
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.Transaction;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class TestQueryForUpdate extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void testForUpdate() {
|
||||
|
||||
if (isH2() || isPostgres()) {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
.forUpdate()
|
||||
.setMaxRows(1)
|
||||
.order().desc("id");
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).contains("for update");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForUpdate_noWait() {
|
||||
|
||||
if (isPostgres() || isOracle()) {
|
||||
ResetBasicData.reset();
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
|
||||
Ebean.beginTransaction();
|
||||
try {
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
.forUpdateNoWait()
|
||||
.setMaxRows(1)
|
||||
.order().desc("id");
|
||||
|
||||
List<Customer> list = query.findList();
|
||||
Customer first = list.get(0);
|
||||
|
||||
assertThat(sqlOf(query)).contains("for update nowait");
|
||||
|
||||
// create a 2nd transaction to test that the
|
||||
// row is locked and we can't acquire it
|
||||
Transaction txn2 = server.createTransaction();
|
||||
try {
|
||||
logger.info("... attempt another acquire using 2nd transaction");
|
||||
Query<Customer> query2 =
|
||||
server.find(Customer.class)
|
||||
.where().idEq(first.getId())
|
||||
.forUpdateNoWait();
|
||||
|
||||
server.findUnique(query2, txn2);
|
||||
assertTrue(false); // never get here
|
||||
} catch (AcquireLockException e) {
|
||||
logger.info("... got AcquireLockException " + e);
|
||||
} finally {
|
||||
txn2.end();
|
||||
}
|
||||
|
||||
} finally {
|
||||
Ebean.endTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.tests.insert;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DataIntegrityException;
|
||||
import io.ebean.Ebean;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
|
||||
public class TestInsertDataIntegrityException extends BaseTestCase {
|
||||
|
||||
|
||||
@Test(expected = DataIntegrityException.class)
|
||||
public void insert_invalidForeignKey() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
// an invalid foreign key value
|
||||
Customer invalidCustomer = Ebean.getReference(Customer.class, 900000);
|
||||
|
||||
Order order = new Order();
|
||||
order.setStatus(Order.Status.NEW);
|
||||
order.setCustomer(invalidCustomer);
|
||||
|
||||
Ebean.save(order);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package org.tests.insert;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DuplicateKeyException;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.annotation.Transactional;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.tests.model.draftable.Document;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestInsertDuplicateKey extends BaseTestCase {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TestInsertDuplicateKey.class);
|
||||
|
||||
@Test(expected = DuplicateKeyException.class)
|
||||
public void insert_duplicateKey() {
|
||||
|
||||
Document doc1 = new Document();
|
||||
doc1.setTitle("ThisIsAUniqueKey");
|
||||
doc1.setBody("one");
|
||||
|
||||
doc1.save();
|
||||
|
||||
Document doc2 = new Document();
|
||||
doc2.setTitle("ThisIsAUniqueKey");
|
||||
doc2.setBody("clashes with doc1");
|
||||
|
||||
doc2.save();
|
||||
}
|
||||
|
||||
@Transactional(batchSize = 100)
|
||||
@Test(expected = DuplicateKeyException.class)
|
||||
public void insertBatch_duplicateKey() {
|
||||
|
||||
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 = Ebean.getDefaultServer()
|
||||
.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
|
||||
Ebean.getDefaultServer().currentTransaction().flushBatch();
|
||||
} catch (DuplicateKeyException e) {
|
||||
log.info("duplicate failed but just continue" + e.getMessage());
|
||||
try {
|
||||
// typically we would use transaction.commitAndContinue()
|
||||
// ... this is a rollback and continue type scenario
|
||||
// ... more sensible to use a second transaction that do this
|
||||
Ebean.getDefaultServer().currentTransaction().getConnection().rollback();
|
||||
} catch (SQLException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Document doc0 = new Document();
|
||||
doc0.setTitle("ThisIsAThirdUniqueKey");
|
||||
doc0.setBody("insertTheBatch_duplicateKey_catchAndContinue-1");
|
||||
doc0.save();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user