Environment:
- Java 21
- Spring 7.0.0-M8
- Hibernate 7.1.3
- Example Project: https://github.com/hantsy/spring7-sandbox/blob/master/hibernate
Description
I migrated the Spring 6/Hibernate 6.6 to new Spring 7 stack and taste the new EntityManager
injection via constructor, check the complete file here.
@Repository
@Transactional
public class JpaPostRepository implements PostRepository {
private final EntityManager entityManager;
public JpaPostRepository(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Transactional(readOnly = true)
@Override
public List<Post> findAll() {
//...
}
@Transactional(readOnly = true)
@Override
public Stream<Post> stream() {
//...
}
@Transactional(readOnly = true)
@Override
public List<Post> findByKeyword(String q, Status status, int offset, int limit) {
// ...
}
@Transactional(readOnly = true)
@Override
public Optional<Post> findById(UUID id) {
//...
}
@Override
public Post save(Post Post) {
//...
}
@Override
public int updateStatus(UUID id, Status status) {
//...
}
@Override
public int deleteById(UUID id) {
//...
}
@Override
public int deleteAll() {
//...
}
}
There are two versions (H2 and TestContainers for Postgres) of testing examples in the folder https://github.com/hantsy/spring7-sandbox/tree/master/hibernate/src/test/java/com/example/demo
The H2 based tests is like this.
@SpringJUnitConfig(classes = {PostRepositoryTest.TestConfig.class})
public class PostRepositoryTest {
private final static Logger log = LoggerFactory.getLogger(PostRepositoryTest.class);
@Autowired
PostRepository posts;
@BeforeEach
public void setup() {
var deleted = this.posts.deleteAll();
log.debug("deleted posts: {}", deleted);
}
@Test
public void testSaveAll() {
var data = List.of(
Post.of("test", "content", Status.PENDING_MODERATION),
Post.of("test1", "content1", Status.DRAFT)
);
data.forEach(this.posts::save);
var results = posts.findAll();
assertThat(results.size()).isEqualTo(2);
var resultsByKeyword = posts.findByKeyword("", Status.PENDING_MODERATION, 0, 10);
assertThat(resultsByKeyword.size()).isEqualTo(1);
}
@Test
public void testInsertAndQuery() {
var data = Post.of("test1", "content1", Status.DRAFT);
var saved = this.posts.save(data);
this.posts.findById(saved.getId()).ifPresent(
p -> assertThat(p.getStatus()).isEqualTo(Status.DRAFT)
);
}
@Configuration
@ComponentScan(basePackageClasses = PostRepository.class)
@Import({JpaConfig.class})
static class TestConfig {
@Bean
@Primary
public DataSource embeddedDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}
}
When running the tests, I got the exception:
jakarta.persistence.OptimisticLockException: Row was already updated or
deleted by another transaction for entity
[com.example.demo.model.Post with id 'fcb86432-fecc-4d5a-a2c8-252f2c940007']