2013-05-28 3 views
1

Я использую оптимистичную стратегию при обновлении объектов, установив "<version />" элемент в hbm.xml s. Он отлично работает при обновлении одного объекта. Но эта стратегия не при рассмотрении данного сценария:Как использовать оптимистичную блокировку с гибернацией при изменении полей

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


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

и существует ограничение: A Ресурс не должен иметь SalesPlan сек с перекрытой dateRange.For Например:

Учитывая есть Ресурс под названием «Hippoom курорт»

И это имеет SalesPlan начиная с 1 ноября 2013 года до ноября 2013 года 2

Когда я хочу добавить SalesPlan в диапазоне от 2 ноя 2013 по ноябрь 2, 2013

Затем он должен потерпеть неудачу по перекрытой диапазон дат

Я должен реализовать это в Java, потому что база данных уникальна ключ не работает в этом «диапазоне» case.The код выглядит следующим образом:

@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; 
} 

Принести все существовали SalesPlan S из базы данных в DuplicateSalesPlanSpecification, чтобы проверить, не отменяет ли новое 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 

------ Пересмотренный --------

версия Гибернация 3.6.10.FINAL.Is ли какие-либо возможности я могу F ix это?

+0

Из вашего кода я не вижу изменений, внесенных в объект SalesPlan или Resource. Поэтому, если нет более кода (тогда, пожалуйста, опубликуйте его), нет никаких причин для обновления, потому что изменений нет. –

+0

Извините, я не дал понять. Я хочу сохранить «SalesPlan» и проверить, не изменился ли «ресурс» другими. См. Пересмотренный контент. – Hippoom

+0

Почему вы не используете HQL для этого с ограничениями вместо того, чтобы пытаться исправить это в сущности? –

ответ

0

Я нахожу временное решение. Добавить логическое поле на ресурс, как:

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

    private boolean dirty = false; 

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

Это поле ничего в области не значит, но, прежде чем обновить ресурс, я могу использовать alwaysMakeDirty(), чтобы запустить SQL обновления.

Я знаю, что это довольно сложно, но это работает.

0

Попробуйте em.Lock (класс, PrimaryKey, LockModeType) с

LockModeType.OPTIMISTIC - это одно проверить версию в конце транзакции в случае того, что кто-то меняет его в середине и в конце концов рулонов назад или LockModeType.OPTIMISTIC_FORCE_INCREMENT - этот всегда обновляет и проверяет версию в конце транзакции и откатывается, если обязательно