我创建了一个函数,该函数试图在启用了版本的DB中保存某些内容,因此它可以给出乐观锁异常。我捕获到异常,然后从数据库中获取后再次尝试。我还使用@transactional注释每次启动新事务。但是,甚至在调用保存功能之前,我都会收到org.springframework.orm.ObjectOptimisticLockingFailureException。
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void handleExecution(@NonNull final Execution execution, final Map<String, Object> data, final String pattern) {
log.info("Processing notification pattern {} with data {} for execution {}",pattern,data,execution);
if (ExecutionStatus.PROCESSING.equals(execution.getStatus()) || ExecutionStatus.WAITING.equals(execution.getStatus())) {
//Put the received notification in the execution queue
List<Map<String, Object>> notificationQueue = execution.getNotificationQueue();
Map<String,Object> notificationMap = new HashMap<>();
notificationMap.put(pattern, data);
notificationQueue.add(notificationMap);
execution.setNotificationQueue(notificationQueue);
try
{
executionBuilder.save(execution);
}
catch(OptimisticLockingFailureException e)
{
log.error("Save of execution {} failed due to optimistic locking, retrying",execution);
//Fetch the object again and call again
Optional<Execution> savedExecution = executionBuilder.findOne(execution.getId());
if(savedExecution.isPresent())
{
handleExecution(savedExecution.get(),data, pattern);
}
}
}
}
我得到的详细异常是:
2018-07-11 08:09:39.408 INFO 8251 --- [thread_pool_executor-45]
o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of
batch it still contained JDBC statements
2018-07-11 08:09:39.408 ERROR 8251 --- [thread_pool_executor-45] reactor.bus.EventBus : Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:320) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at com.gor.platform.process.support.service.builder.ExecutionBuilderImpl$$EnhancerBySpringCGLIB$$a036b2e6.patch(<generated>) ~[process-service-2.0-SNAPSHOT.jar:2.0-SNAPSHOT]
at com.gor.platform.process.support.service.event.receiver.ProcessEventReceiver.accept(ProcessEventReceiver.java:58) ~[process-service-2.0-SNAPSHOT.jar:2.0-SNAPSHOT]
at com.gor.platform.process.support.service.event.receiver.ProcessEventReceiver.accept(ProcessEventReceiver.java:23) ~[process-service-2.0-SNAPSHOT.jar:2.0-SNAPSHOT]
at reactor.bus.EventBus$3.accept(EventBus.java:317) ~[reactor-bus-2.0.8.RELEASE.jar:na]
at reactor.bus.EventBus$3.accept(EventBus.java:310) ~[reactor-bus-2.0.8.RELEASE.jar:na]
at reactor.bus.routing.ConsumerFilteringRouter.route(ConsumerFilteringRouter.java:72) ~[reactor-bus-2.0.8.RELEASE.jar:na]
at reactor.bus.EventBus.accept(EventBus.java:591) [reactor-bus-2.0.8.RELEASE.jar:na]
at reactor.bus.EventBus.accept(EventBus.java:63) [reactor-bus-2.0.8.RELEASE.jar:na]
at reactor.core.dispatch.AbstractLifecycleDispatcher.route(AbstractLifecycleDispatcher.java:160) [reactor-core-2.0.8.RELEASE.jar:na]
at reactor.core.dispatch.MultiThreadDispatcher$MultiThreadTask.run(MultiThreadDispatcher.java:74) [reactor-core-2.0.8.RELEASE.jar:na]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:67) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:54) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:46) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3082) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2961) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3341) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:145) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:582) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:465) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2963) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2339) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:485) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
executionBuilder.save内部调用dao.save,在堆栈跟踪中看不到。为什么甚至在调用保存之前就抛出此异常。调用save时会捕获异常,并且一切正常。但是有时会在没有保存的情况下抛出此异常,因此不会被捕获。
我的直觉表明它与@Transactional有关。
有关信息,我的应用程序是多线程的,许多线程可能同时修改相同的数据。
任何帮助将不胜感激。
答案 0 :(得分:2)
您可以使用控制器内的spring retry选项处理乐观锁。 下载该课程
import org.springframework.retry.annotation.Retryable;
例如
@RequestMapping(value = CommonConstants.DETAILS_ADD_OR_UPDATE, method = RequestMethod.POST)
@Retryable(value = { StaleObjectStateException.class,
HibernateOptimisticLockingFailureException.class }, maxAttempts = 1, backoff = @Backoff(delay = 5000))
public ResponseJson addOrUpdate(@RequestBody User user, HttpServletRequest request) {
try{
responseJson.setResponse(adminService.update(userId, user));
}
catch (DataIntegrityViolationException | ConstraintViolationException e) {
ErrorInfo errorInfo = errorCodeHelper.getErrorInfo(CommonConstants.E1071_ERROR_CODE,
CommonConstants.E1071_ERROR_DESCRIPTION);
throw new ServiceException(errorInfo);
}
return responseJson;
}
这是方法顶部的重要补充
@Retryable(value = { StaleObjectStateException.class,
HibernateOptimisticLockingFailureException.class }, maxAttempts = 1, backoff = @Backoff(delay = 5000))
答案 1 :(得分:0)
ObjectOptimisticLockingFailureException 在交易完成后发生。
如果您要进行1或2次重试: 在控制器中,您可以处理faizakram给出的内容:
try {
service.method_name(requestObj);
} catch (ObjectOptimisticLockingFailureException e) {
try {
service.method_name(requestObj);
} catch (ObjectOptimisticLockingFailureException oex) {
//throw error here
}
}
在使用中:
method_name() throws ObjectOptimisticLockingFailureException{
//business loginc
}