Я использую Java SE и изучаю использование постоянного API (toplink-essentials) для управления объектами в БД Derby.Примечание: это (дистанционное обучение) работа в университете, но это не «домашняя работа», эта проблема возникает в материалах курса.
У меня есть два потока, работающих с одним и тем же набором сущностей.Моя проблема заключается в том, что, как бы я ни пытался, сущности в наборе результатов запроса (запрос, выполненный в транзакции) в одном потоке можно изменить, чтобы набор результатов больше не действовал для остальной части транзакции.
например, из одного потока выполняется эта операция:
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()
возобновляет свой результат запроса. Набор недействителен, и цена проданного предмета обновляется до цены, отличной от той, по которой он был продан.(Магазин хочет вести учет предметов, которые были проданы в БД).Поскольку происходят параллельные транзакции, я использую разные EntityManager
для каждого потока (от одной и той же фабрики).
Возможно ли (с помощью блокировки или какого-либо распространения контекста) предотвратить результаты запросастановится «недействительным» во время (прерванной) транзакции?У меня есть идея, что именно такой сценарий предназначен для Java EE, но я хочу знать, возможно ли его реализовать в Java SE.
Редактировать:
Взять Vineet иСовет Паскаля: использование аннотации @Version
в классе сущности (с дополнительным столбцом БД) приводит к сбою большой транзакции (updatePrices()
) с OptimisticLockException
.Это очень дорого, если это происходит в конце большого набора результатов запроса.Есть ли способ заставить мой запрос (внутри updatePrices()
) заблокировать соответствующие строки, заставляя поток внутри sellInstrument()
либо блокировать, либо прерывать, генерировать исключение (а затем прерывать)?Это было бы намного дешевле.(Из того, что я понимаю, у меня нет пессимистической блокировки в Toplink Essentials).