我有相同的模块连接在两台服务器上运行的数据库(后面和前面)。它与同一个数据库连接。
我使用JPA(Hibernate实现)和Spring事务管理。
我有以下问题:
我必须更新tableA中的fieldA,其中MAX值为两个不同字段中的1个(tableA中的fieldA,tableB中的fieldB)
情况1:
更新前
TABLEA fA = 100
tableB的 fB = 102
更新后
TABLEA fA = 103
tableB的 fB = 102
情况2:
更新前
TABLEA fA = 102
tableB的 fB = 100
更新后
TABLEA fA = 103
tableB的 fB = 100
使用此代码的方法是事务性的,并且在之前执行操作(如创建实体)。因此,在提交事务之前,如果另一个应用程序试图获取该值,它将过时并且它将在fieldA中保存相同的值。 Hibernate会话因分布式系统而异。
我不能在数据库中使用序列(法律问题,因为它是关于发票)或Hibernate的分布式缓存(系统问题)
我该怎么做?
感谢
答案 0 :(得分:2)
您可以使用锁定。适当的锁定类型取决于您的使用案例。
如果并发更新的概率很低,请使用乐观锁定。如果发生更新冲突,请捕获Exception
,刷新实体,重新应用更改并重试提交。
如果您使用乐观锁定,建议您向实体添加@Version
字段。不保证不支持没有版本字段的乐观锁定。
如果并发修改的概率很高,请使用悲观锁定。因此,您可以序列化行上的写入。请注意,这种类型的锁定可能会产生瓶颈,因为更新和其他事务的事务队列在获取锁之前会超时。
为了最小化lokc时间,您可以对单个查询应用锁定:
query.setLockMode(LockMode.WRITE)
编辑:锁可能安全地在分布式环境中使用。
乐观锁定在提交时(或等效)检查数据库中的@Version
字段时实现 - 具有读提交隔离(默认),不存在丢失对实体的已提交更改的风险
悲观锁定在数据库级别实施,通常使用SELECT FOR UPDATE
或类似。所以你不必担心。
答案 1 :(得分:1)
你需要悲观锁定。使用Hibernate,您可以在JDBC或事务级别执行此操作。
阅读hibernate手册中的chapter about locking。
答案 2 :(得分:0)
我不知道我是否理解你的问题,但也许在你的DAO中你可以准备一种方法,你可以做一些事情
DetachedCriteria dc = DetachedCriteria.forClass(ClassA);
dc.setProjection(Projections.max("id"));
logger.info(svc.getMax(dc));
获得最大值后,您可以更新另一个表
安吉洛