use of org.jpwh.model.concurrency.version.Bid in project microservices by pwillhan.
the class Versioning method storeItemAndBids.
public TestData storeItemAndBids() throws Exception {
UserTransaction tx = TM.getUserTransaction();
tx.begin();
EntityManager em = JPA.createEntityManager();
Long[] ids = new Long[1];
Item item = new Item("Some Item");
em.persist(item);
ids[0] = item.getId();
for (int i = 1; i <= 3; i++) {
Bid bid = new Bid(new BigDecimal(10 + i), item);
em.persist(bid);
}
tx.commit();
em.close();
return new TestData(ids);
}
use of org.jpwh.model.concurrency.version.Bid in project microservices by pwillhan.
the class Versioning method forceIncrement.
// TODO This throws the wrong exception!
// @Test(expectedExceptions = OptimisticLockException.class)
@Test(expectedExceptions = org.hibernate.StaleObjectStateException.class)
public void forceIncrement() throws Throwable {
final TestData testData = storeItemAndBids();
Long ITEM_ID = testData.getFirstId();
UserTransaction tx = TM.getUserTransaction();
try {
tx.begin();
EntityManager em = JPA.createEntityManager();
/*
The <code>find()</code> method accepts a <code>LockModeType</code>. The
<code>OPTIMISTIC_FORCE_INCREMENT</code> mode tells Hibernate that the version
of the retrieved <code>Item</code> should be incremented after loading,
even if it's never modified in the unit of work.
*/
Item item = em.find(Item.class, ITEM_ID, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
Bid highestBid = queryHighestBid(em, item);
// Now a concurrent transaction will place a bid for this item, and
// succeed because the first commit wins!
Executors.newSingleThreadExecutor().submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
UserTransaction tx = TM.getUserTransaction();
try {
tx.begin();
EntityManager em = JPA.createEntityManager();
Item item = em.find(Item.class, testData.getFirstId(), LockModeType.OPTIMISTIC_FORCE_INCREMENT);
Bid highestBid = queryHighestBid(em, item);
try {
Bid newBid = new Bid(new BigDecimal("44.44"), item, highestBid);
em.persist(newBid);
} catch (InvalidBidException ex) {
// Ignore
}
tx.commit();
em.close();
} catch (Exception ex) {
// This shouldn't happen, this commit should win!
TM.rollback();
throw new RuntimeException("Concurrent operation failure: " + ex, ex);
}
return null;
}
}).get();
try {
/*
The code persists a new <code>Bid</code> instance; this does not affect
any values of the <code>Item</code> instance. A new row will be inserted
into the <code>BID</code> table. Hibernate would not detect concurrently
made bids at all without a forced version increment of the
<code>Item</code>. We also use a checked exception to validate the
new bid amount; it must be greater than the currently highest bid.
*/
Bid newBid = new Bid(new BigDecimal("44.44"), item, highestBid);
em.persist(newBid);
} catch (InvalidBidException ex) {
// Bid too low, show a validation error screen...
}
/*
When flushing the persistence context, Hibernate will execute an
<code>INSERT</code> for the new <code>Bid</code> and force an
<code>UPDATE</code> of the <code>Item</code> with a version check.
If someone modified the <code>Item</code> concurrently, or placed a
<code>Bid</code> concurrently with this procedure, Hibernate throws
an exception.
*/
tx.commit();
em.close();
} catch (Exception ex) {
throw unwrapCauseOfType(ex, org.hibernate.StaleObjectStateException.class);
} finally {
TM.rollback();
}
}
Aggregations