使用Spring处理Hibernate乐观锁定
我使用的是Hibernate和Spring数据,它在插入或更新实体时将执行乐观锁定,如果数据库中的版本与要持久化的版本不匹配,它将抛出异常使用Spring处理Hibernate乐观锁定,spring,hibernate,Spring,Hibernate,我使用的是Hibernate和Spring数据,它在插入或更新实体时将执行乐观锁定,如果数据库中的版本与要持久化的版本不匹配,它将抛出异常StaleObjectStateException,在Spring中,您需要用ObjectOptimisticLockingFailureException捕获它 我要做的是捕获异常并要求用户刷新页面,以便从数据库中获取最新数据,如下所示: public void cancelRequest() { try { request.
StaleObjectStateException
,在Spring中,您需要用ObjectOptimisticLockingFailureException
捕获它
我要做的是捕获异常并要求用户刷新页面,以便从数据库中获取最新数据,如下所示:
public void cancelRequest()
{
try
{
request.setStatus(StatusEnum.CANCELLED);
this.request = topUpRequestService.insertOrUpdate(request);
loadRequests();
//perform other tasks...
} catch (ObjectOptimisticLockingFailureException ex)
{
FacesUtils.showErrorMessage(null, "Action Failed.", FacesUtils.getMessage("message.pleaseReload"));
}
}
我假设它也可以与下面的代码一起工作,但我还没有测试它
public void cancelRequest()
{
RequestModel latestModel = requestService.findOne(request.getId());
if(latestModel.getVersion() != request.getVersion())
{
FacesUtils.showErrorMessage(null, "Action Failed.", FacesUtils.getMessage("message.pleaseReload"));
}
else
{
request.setStatus(StatusEnum.CANCELLED);
this.request = requestService.insertOrUpdate(request);
loadRequests();
//perform other tasks...
}
}
我需要在调用requestService.insertOrUpdate(request)的任何地方应用此检查代码>我不想一个接一个地应用它们。因此,我决定将检查代码放在函数insertOrUpdate(entity)
本身中
@Transactional
public abstract class BaseServiceImpl<M extends Serializable, ID extends Serializable, R extends JpaRepository<M, ID>>
implements BaseService<M, ID, R>
{
protected R repository;
protected ID id;
@Override
public synchronized M insertOrUpdate(M entity)
{
try
{
return repository.save(entity);
} catch (ObjectOptimisticLockingFailureException ex)
{
FacesUtils.showErrorMessage(null, FacesUtils.getMessage("message.actionFailed"),
FacesUtils.getMessage("message.pleaseReload"));
return entity;
}
}
}
我知道在调用insertOrUpdate
时,我可以通过声明新的模型变量来捕获返回的实体,并将其版本与原始版本进行比较,如果版本相同,则表示持久性失败。但是如果我这样做,我必须在调用insertOrUpdate
的任何地方编写版本检查代码。任何比这更好的方法?能够做到这一点并且不必在所有调用点进行重大代码更改的最接近的方法是研究某种类型的Spring AOP建议,其工作原理类似于Spring的@Transactional
注释
@FacesReloadOnException( ObjectOptimisticLockingFailureException.class )
public void theRequestHandlerMethod() {
// call your service here
}
其思想是,@FacesReloadOnException
注释触发一个around通知,该通知捕获注释值中提供的任何异常,并基本上在抛出任何异常类时处理调用FacesUtils
你可以使用的其他选项不会那么简单,需要你以某种方式接触所有的使用点,这是不可避免的
但是,如果你不想改变服务层的方法返回类型,我当然不会考虑在服务层中放置<代码>尝试/ catch > /Cord>Bug,因为控制器将需要更多的上下文,正如你所指出的。将try/catch
块推到下游的唯一方法是返回某种类型的结果对象,然后控制器可以像这样进行检查
public void someControllerRequestMethod() {
InsertOrUpdateResult result = yourService.insertOrUpdate( theObject );
if ( result.isSuccess() ) {
loadRequests();
}
else {
FacesUtils.showErrorMessage( ... );
}
}
否则,如果您想以某种方式将其集中在web层中,就需要发挥创造性。可能是模仿BaseService
界面的web层实用程序类,如下所示:
public <T extends BaseService, U> U insertOrUpdate(T service, U object, Consumer<U> f) {
try {
U result = service.insertOrUpdate( object );
f.accept( result );
return result;
}
catch ( ObjectOptimisticLockingFailureException e ) {
FacesUtils.showErrorMessage( ... );
}
}
公共U插件更新(T服务、U对象、消费者f){
试一试{
U结果=service.insertOrUpdate(对象);
f、 接受(结果);
返回结果;
}
捕获(对象优化锁定失败异常e){
面部表情信息(…);
}
}
但是坦率地说,除非你有很多呼叫站点与这样一个消费者的泛化非常相似,否则你可能会发现泛化它比仅仅将try/catch
块放在控制器本身更努力、更努力
public <T extends BaseService, U> U insertOrUpdate(T service, U object, Consumer<U> f) {
try {
U result = service.insertOrUpdate( object );
f.accept( result );
return result;
}
catch ( ObjectOptimisticLockingFailureException e ) {
FacesUtils.showErrorMessage( ... );
}
}