1

"<version />"通过在 hbm.xml 中设置元素来更新实体时,我使用了乐观的策略。当我更新单个实体时它工作正常。但是这种策略在处理这种情况时失败了:

public class SalesPlan {
    //omitted fields
    private Resource resource;
    private DateRange dateRange;
}


public class Resource {
    //omitted fields
    private int version = 1;
}

并且有一个约束:资源不应具有具有重叠 dateRange 的 SalesPlan 。例如

鉴于有一个名为“Hippoom 度假村”的资源

它的销售计划 从 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;
}

我从DuplicateSalesPlanSpecification中的数据库中获取所有现有的SalesPlan以检查新的SalesPlan 是否违反约束。我想在最后一步更新资源(检查资源中的版本号)以防并发操作。但我注意到没有更新 sql,因为资源不脏。

——————修改—————————</p>

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 fetch sql 可能会过时

| 第一笔交易开始|
| | 第二笔交易开始
| 选择资源 |
| | 选择资源
| 选择所有销售计划 |
| | 选择所有销售计划
| 根据所有承诺的销售计划进行验证 |
| | 根据所有承诺的销售计划进行验证
| 插入销售计划 |
| | 插入销售计划
| 更新资源以检查版本 |
| | 更新资源以检查版本
| 提交交易 |
| | 因为版本脏了所以回滚

——————修改—————————</p>

Hibernate 版本是 3.6.10.FINAL。我可以解决这个问题吗?

4

2 回答 2

0

我找到了一个临时解决方案。我在 Resource 上添加了一个布尔字段,例如:

public class Resource {
    //omitted fields
    private int version = 1;

    private boolean dirty = false;

    public void alwaysMakeDirty() {
        this.dirty = !dirty;
    }
}

这个字段在域中没有任何意义,但在我更新资源之前,我可以使用 alwaysMakeDirty() 来触发更新 sql。

我知道这很棘手,但它确实有效。

于 2013-05-31T06:37:18.607 回答
0

尝试使用 em.Lock (class, primaryKey, LockModeType)

LockModeType.OPTIMISTIC - 这个在事务结束时检查版本,以防有人在中间更改它并最终回滚或LockModeType.OPTIMISTIC_FORCE_INCREMENT - 这个总是在事务结束时更新并检查版本并回滚如果有必要

于 2014-02-04T18:40:10.303 回答