Spring Boot: org.hibernate.StaleObjectStateException — строка была обновлена ​​или удалена другой транзакциейJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Spring Boot: org.hibernate.StaleObjectStateException — строка была обновлена ​​или удалена другой транзакцией

Сообщение Anonymous »

Я столкнулся с ObjectOptimisticLockingFailureException, вызванным StaleObjectStateException при попытке сохранить объект FlightInstance в моем приложении Spring Boot. Полная трассировка стека выглядит следующим образом:

Код: Выделить всё

rg.springframework.orm.ObjectOptimisticLockingFailureException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [app.bola.flywell.data.model.flight.FlightInstance#16f60701-d478-45ca-bbd4-59fc53aa4ca3]

at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:325)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:560)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:343)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:160)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:165)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)
at jdk.proxy2/jdk.proxy2.$Proxy193.save(Unknown Source)
at app.bola.flywell.services.flightservice.FlyWellFlightInstanceService.createNew(FlyWellFlightInstanceService.java:52)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:380)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at app.bola.flywell.services.flightservice.FlyWellFlightInstanceService$$SpringCGLIB$$0.createNew()
at app.bola.flywell.services.flightservice.FlightInstanceServiceTest.createNewFlightInstance_NewFlightIsCreatedTest(FlightInstanceServiceTest.java:41)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect):  [ a p p . b o l a . f l y w e l l . d a t a . m o d e l . f l i g h t . F l i g h t I n s t a n c e # 1 6 f 6 0 7 0 1 - d 4 7 8 - 4 5 c a - b b d 4 - 5 9 f c 5 3 a a 4 c a 3 ] < b r   / >         a t   o r g . h i b e r n a t e . e v e n t . i n t e r n a l . D e f a u l t M e r g e E v e n t L i s t e n e r . e n t i t y I s D e t a c h e d ( D e f a u l t M e r g e E v e n t L i s t e n e r . j a v a : 4 2 6 ) < b r   / >         a t   o r g . h i b e r n a t e . e v e n t . i n t e r n a l . D e f a u l t M e r g e E v e n t L i s t e n e r . m e r g e ( D e f a u l t M e r g e E v e n t L i s t e n e r . j a v a : 2 1 4 ) < b r   / >         a t   o r g . h i b e r n a t e . e v e n t . i n t e r n a l . D e f a u l t M e r g e E v e n t L i s t e n e r . d o M e r g e ( D e f a u l t M e r g e E v e n t L i s t e n e r . j a v a : 1 5 2 ) < b r   / >         a t   o r g . h i b e r n a t e . e v e n t . i n t e r n a l . D e f a u l t M e r g e E v e n t L i s t e n e r . o n M e r g e ( D e f a u l t M e r g e E v e n t L i s t e n e r . j a v a : 1 3 6 ) < b r   / >         a t   o r g . h i b e r n a t e . e v e n t . s e r v i c e . i n t e r n a l . E v e n t L i s t e n e r G r o u p I m p l . f i r e EventOnEachListener(EventListenerGroupImpl.java:138)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:875)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:846)
at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:258)
at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:248)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:570)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:492)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:253)
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:604)
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:534)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:495)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:253)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:192)
at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:667)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:285)
at org.hibernate.event.internal.DefaultMergeEventListener.merge(DefaultMergeEventListener.java:220)
at org.hibernate.event.internal.DefaultMergeEventListener.doMerge(DefaultMergeEventListener.java:152)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:136)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:89)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:854)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:840)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:320)
at jdk.proxy2/jdk.proxy2.$Proxy181.merge(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:630)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:277)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158)
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:515)
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:284)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:752)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:174)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:149)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:69)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:380)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:138)
...  20 more
Моя настройка
Я использую Spring Boot со следующими зависимостями:

Код: Выделить всё

spring-boot-starter-data-jpa
hibernate-core
Субъект FlightInstance наследует от родительского класса FlyWellModel. Вот соответствующий код:
Родительский класс (FlyWellModel): базовый класс для всех моделей в системе

Код: Выделить всё

public class FlyWellModel {

@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String id;

@Column(nullable = false, unique = true)
private String publicId;

@PrePersist
protected void onCreate() {
if (publicId == null || publicId.isEmpty()) {
publicId = UUID.randomUUID().toString();
}
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("id", id)
.add("publicId", publicId)
.toString();
}
}
Дочерний класс (FlightInstance): объект FlightInstance имеет поле publicId, заполняемое с помощью Аннотация @PrePersist в методе onCreate базового класса FlyWellModel

Код: Выделить всё

@Entity
@Table(name = "flight_instance")
public class FlightInstance extends FlyWellModel {

@Column(nullable = false)
@FlightNumberSequence(name = "flight_number_sequence", startWith = 1000, incrementBy = 3) , изменяя объект до завершения транзакции. Я подозреваю, что эта модификация может привести к тому, что Hibernate будет рассматривать объект как «грязный», что приведет к исключению.
Интересно, что аналогичная настройка отлично работает для Flight[/b].  сущность, которая имеет следующую структуру:
[code]@Entity
public class Flight extends FlyWellModel {

private long duration;
private String arrivalCity;
private String departureCity;
private String displayImage;

@OneToOne(cascade = ALL)
private Airport departureAirport;

@OneToOne(cascade = ALL)
private Airport arrivalAirport;

@OneToMany(mappedBy = "flight", cascade = ALL, fetch = EAGER)
private Set instances = new LinkedHashSet();

public FlightInstance addFlightInstance(FlightInstance newInstance){
newInstance.setFlight(this);
instances.add(newInstance);
return newInstance;
}

}
Проблема
Исключение возникает при вызове метода сохранения в FlightInstanceRepository в уровень обслуживания:
Метод обслуживания:

Код: Выделить всё

@Service
public class FlyWellFlightInstanceService {

@Autowired
private FlightInstanceRepository flightInstanceRepository;

@Override
@Transactional
@Retryable(retryFor = ObjectOptimisticLockingFailureException.class, maxAttempts = 5)
public FlightInstanceResponse createNew(FlightInstanceRequest request) {

Flight flight = flightRepository.findByPublicId(request.getFlightId())
.orElseThrow(() -> new EntityNotFoundException(Constants.ENTITY_NOT_FOUND.formatted("Flight")));

FlightInstance mappedInstance = mapper.map(request, FlightInstance.class);
mappedInstance.setFlight(flight);
mappedInstance.setStatus(SCHEDULED);
mappedInstance.setFlightSeat(new ArrayList());

FlightInstance savedInstance = flight.addFlightInstance(mappedInstance);

flightRepository.save(flight);
return toResponse(savedInstance);
}

private FlightInstanceResponse toResponse(FlightInstance instance) {

FlightInstanceResponse response = mapper.map(instance, FlightInstanceResponse.class);
response.setArrivalAirportName(instance.getFlight().getArrivalAirport().getName());
response.setDepartureAirportName(instance.getFlight().getDepartureAirport().getName());

return response;
}
Наблюдения
  • @PrePersist на FlightInstance: Поле publicId заполняется во время сохранения, что изменяет объект во время операции сохранения.
  • Вмешательство в потоки: я подозреваю, что в игре может участвовать несколько потоков. Пока один поток изменяет объект Flight, другой поток может одновременно изменять связанный с ним объект FlightInstance, вызывая конфликт.
Что я пробовал Пока
  • Я подозреваю, что проблема может быть связана с полем publicId, унаследованным от класса FlyWellModel, в частности с хуком @PrePersist. Для дальнейшей отладки я внес несколько изменений:
  • Отсоединил модель FlightInstance: я полностью удалил связь между моделью FlightInstance и FlyWellModel, гарантируя, что Модель FlightInstance больше не наследуется от FlyWellModel и не имеет поля publicId. Однако я по-прежнему сталкивался с той же ошибкой.
  • Переименовал объект: думаю, проблема может быть связана с конфликтом имен между Flight< /strong> и FlightInstance, я переименовал FlightInstance в Instance, но все равно столкнулся с той же ошибкой.
  • Отключено @PrePersist : Я закомментировал onCreate(), аннотированный @PrePersist в модели FlyWell, и я применил этот метод к модели Flight, но проблема осталась.
Эти изменения заставили меня поверить, что проблема не может быть напрямую связана с publicId или поле Логика @PrePersist. Теперь я еще больше запутался, поскольку эти изменения не устранили ошибку. Что может быть основной причиной и как мне подойти к ее решению?
Мой вопрос
  • Вызывает ли изменение @PrePersist поля publicId исключение StaleObjectStateException? Если да, то как лучше всего с этим справиться?
  • Могут ли несколько потоков одновременно изменять объект FlightInstance, и как я могу проверить или смягчить это в настройке Spring Boot + Hibernate?< /li>
    Почему объект Flight работает без проблем, в то время как объект FlightInstance выдает это исключение при аналогичных условиях?
    4.Как я могу решить эту проблему так что Объект FlightInstance сохраняется правильно, без возникновения StaleObjectStateException
Будем очень признательны за любые рекомендации и идеи! Спасибо!

Подробнее здесь: https://stackoverflow.com/questions/793 ... -or-delete
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»