0

I compare two entity with different type of ID and see different situations in tests. When i use type Long for ID - it's ok. But when UUID it throws ObjectOptimisticLockingFailureException.

POM file:

...
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.6</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
...
<properties>
    <java.version>17</java.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>test</scope>
    </dependency>
            
</dependencies>
...

Configuration file is empty.

First entity:

@Entity
@Table(name = "LONG_ENTITY")
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class LongEntity implements Serializable {

   @Id
   @GeneratedValue
   @EqualsAndHashCode.Include
   private Long id;

   private String name;
}

First repository:

public interface LongEntityRepository extends CrudRepository<LongEntity,Long> {
   List<LongEntity> findByName(String name);
}

First test:

@SpringBootTest
@Transactional
public class LongEntityRepositoryTest {

   @Autowired
   private LongEntityRepository repository;

   @Test
   public void testSaveLong() {
      LongEntity expected = new LongEntity();
      expected.setName("Name");
      expected = repository.save(expected);
      expected.setName("NewName");
      expected = repository.save(expected);
    
      List<LongEntity> result = repository.findByName(expected.getName());

      assertThat(result).as("check result contains expected")
            .contains(expected);
   }
}

it finish ok.

Second entity:

@Entity
@Table(name = "UUID_ENTITY")
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class UuidEntity implements Serializable {

   @Id
   @GeneratedValue
   @EqualsAndHashCode.Include
   private UUID id;

   private String name;
}

Second repository:

public interface UuidEntityRepository extends CrudRepository<UuidEntity,UUID> {
   List<UuidEntity> findByName(String name);
}

Second test:

@SpringBootTest
@Transactional
public class UuidEntityRepositoryTest {

   @Autowired
   private UuidEntityRepository repository;

   @Test
   public void testSaveUuid() {
      UuidEntity expected = new UuidEntity();
      expected.setName("Name");
      expected = repository.save(expected);
      expected.setName("NewName");           // the reason of exception
      expected = repository.save(expected);
    
      List<UuidEntity> result = repository.findByName(expected.getName());

      assertThat(result).as("check result contains expected")
            .contains(expected);
   }
}

It's failure with:

org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; statement executed: update uuid_entity set name=? where id=?; nested exception is 
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; statement executed: update uuid_entity set name=? where id=?
at net.tyt.sample.jpa.UuidEntityRepositoryTest.testSaveUuid(UuidEntityRepositoryTest.java:39)
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; statement executed: update uuid_entity set name=? where id=?
at net.tyt.sample.jpa.UuidEntityRepositoryTest.testSaveUuid(UuidEntityRepositoryTest.java:39)

Somebody know why it hapens?

Igor Tytar
  • 433
  • 1
  • 4
  • 10
  • 1
    Maybe https://stackoverflow.com/questions/2743130/hibernate-batch-update-returned-unexpected-row-count-from-update-0-actual-row will help you – doctore Dec 11 '22 at 08:24
  • What is the ID value being inserted in the tests? UUID generation wasn't supported without more configuration, so you might not have set it up right for the version(s) you are using. – Chris Dec 11 '22 at 21:54
  • thanks for answers. but id generated correctly. and no difference with: @GeneratedValue(generator = "UUID") @GenericGenerator( name = "UUID", strategy = "org.hibernate.id.UUIDGenerator", ) private UUID id; – Igor Tytar Dec 12 '22 at 02:15

1 Answers1

0

I've downgraded spring-boot parent version and it works fine

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.14</version>
    <!--        <version>2.7.6</version> doesn't work -->
    <relativePath/> <!-- lookup parent from repository -->
</parent>
Igor Tytar
  • 433
  • 1
  • 4
  • 10