伟大的工作试图安全地写入锁定您的更改数据。:) 但你可能会走火入魔/做很长的路要走。
首先是一个小问题。不需要调用persist()。对于更新,只需修改 find() 返回的实体的属性。entityManager 自动知道更改并在提交期间将它们写入数据库。仅当您创建新对象并将其首次写入数据库时才需要持久化(或将新子对象添加到父关系并通过 cascade=PERSIST 级联持久化)。
大多数应用程序通过具有自己的单独事务和单独的持久上下文的不同线程对相同数据的“冲突”并发更新的可能性很低。如果这对您来说是正确的,并且您希望最大限度地提高可伸缩性,那么请使用乐观的写入锁,而不是悲观的读取或写入锁。绝大多数 Web 应用程序都是这种情况。它提供完全相同的数据完整性、更好的性能/可扩展性,但您必须(不经常)处理 OptimisticLockException。
乐观写锁定是自动内置的,只需在数据库和实体中具有一个短/整数/长/时间戳属性并在实体中使用@Version对其进行注释,在这种情况下您不需要调用 entityManager.lock()
如果您对上述内容感到满意,并向您的实体添加了 @Version 属性,您的代码将是:
try {
entityManager.getTransaction().begin();
r = entityManager.find(Route.class, r.getPrimaryKey());
r.setRoute(txtRoute.getText());
entityManager.getTransaction().commit();
} catch (OptimisticLockException e) {
// Logging and (maybe) some error handling here.
// In your case you are lucky - you could simply rerun the whole method.
// Although often automatic recovery is difficult and possibly dangerous/undesirable
// in which case we need to report the error back to the user for manual recovery
}
即根本没有显式锁定- 实体管理器自动处理它。
如果您非常需要避免并发数据更新“冲突”,并且很高兴您的代码具有有限的可伸缩性,那么通过悲观的写锁定序列化数据访问:
try {
entityManager.getTransaction().begin();
r = entityManager.find(Route.class, r.getPrimaryKey(), LockModeType.PESSIMISTIC_WRITE);
r.setRoute(txtRoute.getText());
entityManager.getTransaction().commit();
} catch (PessimisticLockException e) {
// log & rethrow
}
在这两种情况下,成功提交或具有自动回滚的异常意味着执行的任何锁定都将自动清除。
干杯。