javaspring-boothibernatespring-data-jpa

Spring Boot 3.4.0 lets integration tests with JPA/Hibernate fail


We have updated from Spring Boot 3.3.6 to version 3.4.0. Now our integrationtests (Annotation @SpringBootTest) with Hibernate/JPA interactions (we're using spring-data-jpa) in it fail suddenly.

@Test
void retrieveAllFahrzeugbewegungenByMuster() throws Exception {
    // Given
    var musterEntity = MusterMetadatenGenerator.createDefaultMuster();
    var musterEntitySaved = musterMetadatenRepository.saveAndFlush(musterEntity); // crashes here
...
}

The creation of the @Entity in createDefaultMuster() is essentially this here:

static <E extends BaseEntity> E createDefaultValues(
      @NotNull final E source,
      @NotNull final LocalDate datumAb,
      @NotNull final LocalDate datumBis
) {
    final Instant now = Instant.now();

    source.setId(UUID.randomUUID());
    source.setDatumAb(datumAb);
    source.setDatumBis(datumBis);
    source.setBearbeitetAm(now);
    source.setErstelltAm(now);

    return source;
}

The @Entity itself looks as below:

@Data
@NoArgsConstructor
@AllArgsConstructor
@MappedSuperclass
public class BaseEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(updatable = false, nullable = false)
  protected UUID id;
...

The exception is:

org.springframework.orm.ObjectOptimisticLockingFailureException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [de.muster.jpa.entity.MusterMetadaten#40add996-a1f9-43f7-a157-cf5692e5ea65] Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [de.muster.jpa.entity.MusterMetadaten#40add996-a1f9-43f7-a157-cf5692e5ea65]

With Spring Boot 3.4.0 comes Hibernate 6.6.x, before it was Hibernate 6.5.x. Is there maybe a breaking change?


Solution

  • Can you check the new entity's @Id property?

    Spring Boot 3.4.0 was upgraded to Hibernate 6.6.2.Final #43100

    There are changes of DefaultMergeEventListener.

    Hibernate 6.5.3.Final (Boot 3.3.5)

    if ( result == null ) {
      //TODO: we should throw an exception if we really *know* for sure
      //      that this is a detached instance, rather than just assuming
      //throw new StaleObjectStateException(entityName, id);
    

    Hibernate 6.6.2.Final (Boot 3.4.0)

    if ( result == null ) {
      LOG.trace( "Detached instance not found in database" );
      // we got here because we assumed that an instance
      // with an assigned id and no version was detached,
      // when it was really transient (or deleted)
      final Boolean knownTransient = persister.isTransient( entity, source );
      if ( knownTransient == Boolean.FALSE ) {
        // we know for sure it's detached (generated id
        // or a version property), and so the instance
        // must have been deleted by another transaction
        throw new StaleObjectStateException( entityName, id );
    

    So you may meet message of "Row was already updated or deleted by another transaction".

    This change can follow below issue:

    If you want to fix the test code, first show your code of MusterMetadatenGenerator.createDefaultMuster().