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?