在没有字段更改的情况下,如何在hibernate中使用乐观锁
当通过在hbm.xml s中设置元素来更新实体时,我使用的是乐观策略。当我更新单个实体时,它工作正常。但这种策略在处理这种情况时失败了:在没有字段更改的情况下,如何在hibernate中使用乐观锁,hibernate,versioning,optimistic-locking,Hibernate,Versioning,Optimistic Locking,当通过在hbm.xml s中设置元素来更新实体时,我使用的是乐观策略。当我更新单个实体时,它工作正常。但这种策略在处理这种情况时失败了: public class SalesPlan { //omitted fields private Resource resource; private DateRange dateRange; } public class Resource { //omitted fields private int versio
public class SalesPlan {
//omitted fields
private Resource resource;
private DateRange dateRange;
}
public class Resource {
//omitted fields
private int version = 1;
}
还有一个约束:资源不应具有日期范围重叠的销售计划。例如:
这里有一个名为Hippoom resort的资源
其销售计划范围为2013年11月1日至2013年11月2日
当我想添加2013年11月2日至2013年11月2日的销售计划时
那么对于重叠的日期范围,它应该失败
我必须用Java实现这一点,因为数据库唯一键在这种情况下不起作用。代码如下所示:
@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;
}
我从重复SalesPlanSpecification中的数据库中获取所有现有的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
在使用乐观策略时,如果有人在另一个事务中插入新的SalesPlan而没有最后一个sql,则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
------修改--------
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
Hibernate版本是3.6.10.FINAL。我有没有可能解决这个问题?我找到了一个临时解决方案。我在资源上添加了一个布尔字段,如:
public class Resource {
//omitted fields
private int version = 1;
private boolean dirty = false;
public void alwaysMakeDirty() {
this.dirty = !dirty;
}
}
这个字段在域中没有任何意义,但是在我更新资源之前,我可以使用AlwaysMaxDirty启动更新sql
我知道这很棘手,但它很有效。试试em。Lock类、primaryKey、LockModeType和
LoMyDyType .Posiv-这是一个在事务结束时检查版本的情况,如果有人在中间改变它,并最终回滚或LoopMoDyType。Opdate IsPixFuffelPosith-这个总是在事务结束时更新并检查版本,如果必须从你的代码中翻转,我就看不到任何版本。您对SalesPlan或资源实体所做的更改。所以,除非有更多的代码,然后请张贴它没有理由更新,因为没有任何变化。对不起,我没有说清楚。我想保存销售计划并检查资源是否未被其他人修改。请查看修改后的帖子内容。为什么您不使用HQL来解决此问题,而不尝试在实体中修复它?@BeenCoding2Long:对不起,我不明白。你能给我看一些示例代码吗?我想要这个更新,以防其他人想同时添加新的销售计划。这将破坏验证,因为大多数数据库只能读取提交的数据。