私はJavaSEを使用しており、永続API(toplink-essentials)を使用してDerbyDBのエンティティを管理する方法について学習しています。注:これは(遠隔教育)大学の仕事ですが、この問題がコースの資料に現れる「宿題」ではありません。
同じエンティティのセットで動作する2つのスレッドがあります。私の問題は、私が試したすべての方法で、1つのスレッドのクエリ結果セット(トランザクション内で実行されるクエリ)内のエンティティを変更して、結果セットが残りのトランザクションで無効になるようにすることができることです。
たとえば、1つのスレッドからこの操作が実行されます。
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()
再開すると、クエリresultSetが無効になり、販売されたアイテムの価格が、販売されたときとは異なる価格に更新されることです。(ショップは、DBで販売されたアイテムの記録を保持したいと考えています)。同時トランザクションが発生しているEntityManager
ため、(同じファクトリからの)スレッドごとに異なるものを使用しています。
(中断された)トランザクション中にクエリの結果が「無効」になるのを防ぐことは(ロックまたはある種のコンテキスト伝播によって)可能ですか?この種のシナリオがJavaEEの目的であると私は考えていますが、私が知りたいのは、JavaSEで実行できるかどうかです。
編集:
VineetとPascalのアドバイスに従う:@Version
エンティティのクラスでアノテーションを使用すると(追加のDB列を使用)、大きなトランザクション(updatePrices()
)が。で失敗しOptimisticLockException
ます。ただし、大量のクエリ結果の最後に発生した場合、これは非常にコストがかかります。クエリ(内部updatePrices()
)に関連する行をロックさせて、内部のスレッドをsellInstrument()
ブロックまたは中止して例外をスローする(その後中止する)方法はありますか?これははるかに安いでしょう。(私が理解していることから、Toplink Essentialsには悲観的なロックはありません)。