#hibernate #jpa #optimistic-locking
#гибернация #jpa #оптимистичная блокировка
Вопрос:
Возникает одно исключение ObjectOptimisticLockingFailureException . Я проверяю журнал и нахожу, что это исключение вызвано запросом select. Это werid.
Вот трассировка стека исключений.
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:317)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:491)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy117.countOtherRoles(Unknown Source)
at net.homecredit.mcd.app.service.UserRolePosService.countOtherRoles(UserRolePosService.java:315)
at net.homecredit.mcd.app.service.UserRolePosService.canRemoveEmployer(UserRolePosService.java:375)
at net.homecredit.mcd.app.service.UserRolePosService.deactivate(UserRolePosService.java:339)
at net.homecredit.mcd.app.service.UserRolePosService.fillRoleData(UserRolePosService.java:241)
at net.homecredit.mcd.app.service.UserRolePosService.fillRoleData(UserRolePosService.java:199)
at net.homecredit.mcd.app.service.UserRolePosService.fillRoleData(UserRolePosService.java:180)
at net.homecredit.mcd.app.service.pos.PosBusinessService.saveUserRole(PosBusinessService.java:224)
at net.homecredit.mcd.app.service.pos.PosBusinessService.updatePos(PosBusinessService.java:121)
at net.homecredit.mcd.app.service.pos.PosBusinessService$FastClassBySpringCGLIB$ad825d06.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:69)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at net.homecredit.mcd.common.security.ForbiddingSecurityInterceptor.invoke(ForbiddingSecurityInterceptor.java:17)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at net.homecredit.mcd.common.aop.AuditInterceptor.invoke(AuditInterceptor.java:21)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656)
at net.homecredit.mcd.app.service.pos.PosBusinessService$EnhancerBySpringCGLIB$7cfba5de.updatePos(<generated>)
at net.homecredit.mcd.app.service.homesis.kafka.HsisKafkaConsumer.updatePos(HsisKafkaConsumer.java:122)
at net.homecredit.mcd.app.service.homesis.kafka.HsisKafkaConsumer.updatePos(HsisKafkaConsumer.java:97)
at net.homecredit.mcd.app.service.homesis.kafka.HsisKafkaConsumer.consumePos(HsisKafkaConsumer.java:73)
at sun.reflect.GeneratedMethodAccessor871.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:180)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:112)
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48)
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:174)
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:82)
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:50)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:975)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:959)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:901)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:786)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:656)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [net.homecredit.mcd.app.domain.Pos#2307536273]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2400)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3202)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3077)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3457)
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:145)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:589)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:50)
at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1398)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1483)
at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1445)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1414)
at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1463)
at net.homecredit.mcd.app.dao.UserRolePosDao.countOtherRoles(UserRolePosDao.java:225)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
... 47 common frames omitted
Журнал показывает, что при обновлении таблицы POS возникает ошибка оптимистичной блокировки. Эта строка
"at net.homecredit.mcd.app.dao.UserRolePosDao.countOtherRoles(UserRolePosDao.java:225)"
, вызывает эту оптимистическую ошибку. Я проверяю этот код.
public Integer countOtherRoles(User user, UserRolePos userRole) {
return em.createNamedQuery(UserRolePos.COUNT_OTHER_ROLE_FOR_USER, Long.class)
.setParameter("user", user)
.setParameter("userRole", userRole)
.getSingleResult().intValue();
}
Связанный запрос выглядит следующим образом
@NamedQuery(name = UserRolePos.COUNT_OTHER_ROLE_FOR_USER,
query = "SELECT COUNT(urp) FROM UserRolePos urp "
"WHERE urp.user = :user "
"AND urp != :userRole "
)
Это просто запрос выбора с другой таблицей пользовательских ролей, почему это вызывает оптимистическую ошибку блокировки с таблицей POS?
Ответ №1:
Если вы внимательно посмотрите на stacktrace, вы заметите, что Hibernate выполняет «автоматическую очистку». Это происходит, когда у вас есть «грязные» объекты в вашем контексте сохранения и вы пытаетесь выполнить запрос, который использует таблицы, которые пересекаются с таблицами грязных объектов. Если он не очистит грязные записи, вы можете получить неправильные результаты.
Комментарии:
1. Спасибо, я думаю, в контексте есть один «грязный» объект POS. Но как hibernate сообщает, что это грязная сущность? Он сравнивает версии между строками сущности и таблицы в фоновом режиме?
2. Когда Hibernate загружает объект, он запоминает состояние. Поскольку объект связан с контекстом сохранения, он проверит, не загрязнен ли он. Так что, по сути, да, Hibernate сравнивает это в фоновом режиме, но он не делает этого, выдавая отдельный запрос.