Spring Boot: org.hibernate.StaleObjectStateException – Zeile wurde durch eine andere Transaktion aktualisiert oder gelösJava

Java-Forum
Guest
 Spring Boot: org.hibernate.StaleObjectStateException – Zeile wurde durch eine andere Transaktion aktualisiert oder gelös

Post by Guest »

Beim Versuch, eine FlightInstance-Entität in meiner Spring Boot-Anwendung zu speichern, stoße ich auf eine ObjectOptimisticLockingFailureException, die durch eine StaleObjectStateException verursacht wurde. Der vollständige Stack-Trace lautet wie folgt:

Code: Select all

org.springframework.orm.ObjectOptimisticLockingFailureException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [app.bola.flywell.data.model.flight.FlightInstance#79e7f6b2-9364-49f4-97f6-cf5afa537b6b]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:325)
at app.bola.flywell.services.flightservice.FlyWellFlightInstanceService.createNew(FlyWellFlightInstanceService.java:59)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
...
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [app.bola.flywell.data.model.flight.FlightInstance#79e7f6b2-9364-49f4-97f6-cf5afa537b6b]
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:426)
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)
...
Mein Setup
Ich verwende Spring Boot mit den folgenden Abhängigkeiten:

Code: Select all

spring-boot-starter-data-jpa
hibernate-core
Die Entität FlightInstance erbt von einer übergeordneten Klasse namens FlyWellModel. Hier ist der relevante Code:
Übergeordnete Klasse (FlyWellModel): Die Basisklasse für alle Modelle im System

Code: Select all

public class FlyWellModel {

@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String id;
@Column(nullable = false, unique = true)
private String publicId;
@CreatedDate
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime lastModifiedDate;
@CreatedBy
@Builder.Default
private String createdBy = "SYSTEM";
private String createdByRole;
@LastModifiedBy
private String lastModifiedBy;

@PrePersist
protected void onCreate() {
if (publicId == null || publicId.isEmpty()) {
publicId = UUID.randomUUID().toString();
}
}
}
Untergeordnete Klasse (FlightInstance): Die FlightInstance-Entität verfügt über ein publicId-Feld, das mit a gefüllt wird @PrePersist-Annotation in der onCreate-Methode aus der Basisklasse FlyWellModel

Code: Select all

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

@Column(nullable = false)
private String flightNumber;
@ManyToOne(fetch = FetchType.LAZY)
@ToString.Exclude
private Flight flight;
// Other specific fields
}
Wenn die Speichermethode aufgerufen wird, generiert der @PrePersist-Hook einen Wert für die publicId und ändert die Entität, bevor die Transaktion abgeschlossen wird . Ich vermute, dass diese Änderung dazu führen könnte, dass Hibernate die Entität als „schmutzig“ behandelt, was zu der Ausnahme führt.
Interessanterweise funktioniert ein ähnliches Setup perfekt für den Flight Entität, die wie folgt aufgebaut ist:

Code: Select all

@Entity
public class Flight extends FlyWellModel {
private long duration;
private String arrivalCity;
private String departureCity;
private String displayImage;

@OneToOne(cascade = CascadeType.ALL)
private Airport departureAirport;

@OneToOne(cascade = CascadeType.ALL)
private Airport arrivalAirport;

@OneToMany(mappedBy = "flight", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List flightInstances;
}
Das Problem
Die Ausnahme tritt auf, wenn die Speichermethode für das FlightInstanceRepository aufgerufen wird die Service-Schicht:
Service-Methode:

Code: Select all

@Service
public class FlyWellFlightInstanceService {
@Autowired
private FlightInstanceRepository flightInstanceRepository;

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

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

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

FlightInstance savedInstance = flightInstanceRepository.save(mappedFlightInstance);

flight.getFlightInstances().add(savedInstance);
flightRepository.save(flight);
return flightInstanceResponse(savedInstance);
}
}
Beobachtungen
  • @PrePersist auf FlightInstance: The Das Feld „publicId“ wird zum Zeitpunkt der Persistenz ausgefüllt, wodurch die Entität während des Speichervorgangs geändert wird.
  • Thread-Interferenz: Ich vermute, dass mehrere Threads im Spiel sind. Während ein Thread die Flight-Entität ändert, ändert möglicherweise ein anderer Thread gleichzeitig die zugehörige FlightInstance-Entität, was zu einem Konflikt führt.
Meine Frage
  • Verursacht die @PrePersist-Änderung am publicId-Feld die StaleObjectStateException? Wenn ja, wie geht man damit am besten um?
  • Könnten mehrere Threads gleichzeitig die FlightInstance-Entität ändern, und wie kann ich dies in einem Spring Boot + Hibernate-Setup überprüfen oder entschärfen?< /li>
    Warum funktioniert die Flight-Entität ohne Probleme, während die FlightInstance-Entität diese Ausnahme unter ähnlichen Bedingungen auslöst?
    4.Wie kann ich dieses Problem beheben, damit die FlightInstance-Entität gespeichert wird? richtig, ohne zu stoßen StaleObjectStateException
Jede Anleitung oder Einsicht wäre sehr dankbar! Danke!

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post