我正在使用 Java SE 并了解如何使用持久性 API(toplink-essentials)来管理 Derby DB 中的实体。注意:这是(远程学习)大学作业,但不是“家庭作业”,这个问题出现在课程材料中。
我有两个线程在同一组实体上运行。我的问题是,我尝试过的每一种方式,都可以修改一个线程中查询结果集中的实体(在事务中执行的查询),以便结果集对事务的其余部分不再有效。
例如,从一个线程执行此操作:
static void updatePrices(EntityManager manager, double percentage) {
EntityTransaction transaction = manager.getTransaction();
transaction.begin();
Query query = manager.createQuery("SELECT i FROM Instrument i where i.sold = 'no'");
List<Instrument> results = (List<Instrument>) query.getResultList();
// force thread interruption here (testing non-repeatable read)
try { Thread.sleep(2000); } catch (Exception e) { }
for (Instrument i : results) {
i.updatePrice(percentage);
}
transaction.commit();
System.out.println("Price update commited");
}
如果使用此方法从另一个线程中断它:
private static void sellInstrument(EntityManager manager, int id)
{
EntityTransaction transaction = manager.getTransaction();
transaction.begin();
Instrument instrument = manager.find(Instrument.class, id);
System.out.println("Selling: " + instrument.toFullString());
instrument.setSold(true);
transaction.commit();
System.out.println("Instrument sale commited");
}
可能发生的情况是,当线程updatePrices()
恢复时,它的查询结果集无效,并且已售商品的价格最终会更新为与出售时不同的价格。(商店希望保留在 DB 中出售的商品的记录)。由于发生并发事务,我EntityManager
为每个线程(来自同一工厂)使用不同的事务。
是否有可能(通过锁定或某种上下文传播)防止查询结果在(中断的)事务期间变为“无效”?我有一个想法,这种场景是 Java EE 的用途,但我想知道它在 Java SE 中是否可行。
编辑:
接受 Vineet 和 Pascal 的建议:@Version
在实体的 Class 中使用注解(带有一个额外的 DB 列)会导致大型事务 ( updatePrices()
) 以OptimisticLockException
. 但是,如果它发生在大量查询结果的末尾,这是非常昂贵的。有什么方法可以使我的查询(内部updatePrices()
)锁定相关行,从而导致内部线程sellInstrument()
阻塞或中止引发异常(然后中止)?这会便宜得多。(据我了解,我在 Toplink Essentials 中没有悲观锁定)。