【发布时间】:2011-03-16 03:18:02
【问题描述】:
我正在使用 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 的建议:在实体的 Class 中使用 @Version 注释(带有额外的 DB 列)会导致大型事务(updatePrices())以OptimisticLockException 失败。但是,如果它发生在大量查询结果的末尾,这是非常昂贵的。有什么方法可以使我的查询(在 updatePrices() 内)锁定相关行,从而导致 sellInstrument() 内的线程阻塞或中止引发异常(然后中止)?这会便宜得多。 (据我了解,我在 Toplink Essentials 中没有悲观锁定)。
【问题讨论】:
标签: jpa persistence entitymanager java