我通过在hbm.xml中设置"<version />"
元素来更新实体时使用乐观策略。当我更新单个实体时,它工作正常。但是在处理这种情况时,这种策略失败了:
public class SalesPlan {
//omitted fields
private Resource resource;
private DateRange dateRange;
}
public class Resource {
//omitted fields
private int version = 1;
}
并且存在一个约束:资源不应该具有重叠日期的 SalesPlan 。例如:
鉴于资源已命名为&#34; Hippoom度假村&#34;
2013年11月1日至2013年11月2日 SalesPlan
当我想添加从2013年11月2日到2013年11月2日的 SalesPlan 时
然后重叠的日期范围应该失败
我必须在Java中实现它,因为数据库唯一键在此&#34;范围内不起作用&#34; case。代码如下:
@Transactional
@Override
public SalesPlan handle(CreateSalesPlanCommand command) {
Resource resource = resourceRepository.findBy(command.getResourceId());
SalesPlan salesPlan = //omitted init codes
DuplicateSalesPlanSpecification spec = aDuplicateSpec();
if (spec.isSatisfiedBy(salesPlan)) {
throw new DuplicateSalesPlanException(salesPlan);
}
salesPlanRepository.store(salesPlan);
resourceRepository.store(salesPlan.getResource());
return salesPlan;
}
我从 DuplicateSalesPlanSpecification 中的数据库中获取所有已存在的 SalesPlan ,以检查新的 SalesPlan 是否违反了约束。我想更新在并发操作的情况下,最后一步中的资源(检查资源中的版本号)。但我注意到没有更新sql,因为资源不脏。
------ --------修订
select
resource0_.RESOURCE_ID as RESOURCE1_0_0_,
resource0_.version as version0_0_,
//omitted columns
from
T_IRS_RESOURCE resource0_
where
resource0_.RESOURCE_ID=?
select
this_.SALES_PLAN_ID as SALES1_1_0_,
this_.version as version1_0_,
this_.RESOURCE_ID as RESOURCE3_1_0_,
this_.DATE_RANGE_START as DATE4_1_0_,
this_.DATE_RANGE_END as DATE5_1_0_,
//omitted columns
from
T_IRS_SALES_PLAN this_
where
this_.RESOURCE_ID=?
order by
this_.DATE_RANGE_START desc,
this_.SALES_PLAN_ID desc
insert into T_IRS_SALES_PLAN//omitted columns
update T_IRS_RESOURCE set version = version + 1
where RESOURCE_ID = ?
and VERSION = ? //this sql missed
在使用乐观策略时,如果有人在没有最后一个sql的情况下在另一个事务中插入新的SalesPlan,则SalesPlan获取sql可能是陈旧的
| the first transaction started | | | the second transaction started | select resource | | | select resource | select all salesplans | | | select all salesplans | validate base on all committed salesplans | | | validate base on all committed salesplans | insert salesplan | | | insert salesplan | update resource to check version | | | update resource to check version | commit txn | | | rolls back because version is dirty
------ --------修订
Hibernate版本是3.6.10.FINAL。我有什么可能解决这个问题吗?
答案 0 :(得分:0)
我找到了一个临时解决方案。我在Resource上添加了一个布尔字段,如:
public class Resource {
//omitted fields
private int version = 1;
private boolean dirty = false;
public void alwaysMakeDirty() {
this.dirty = !dirty;
}
}
此字段在域中没有任何意义,但在更新资源之前,我可以使用alwaysMakeDirty()来触发更新sql。
我知道这很棘手,但确实有效。
答案 1 :(得分:0)
使用
尝试em.Lock(class,primaryKey,LockModeType)LockModeType.OPTIMISTIC - 如果某人在中间更改了该版本并最终回滚或 LockModeType.OPTIMISTIC_FORCE_INCREMENT ,则检查该事务结束时的版本 - 这个总是在事务结束时更新并检查版本并在必要时回滚