Spring JPA仓库事务性

42

关于Spring JPA repositories的事务性问题,我有一个快速的问题。

我有一个未标记为事务性的服务,调用了Spring JPA repository方法。

userRegistrationRepository.deleteByEmail(email);

并且它被定义为

@Repository
public interface UserRegistrationRepository extends JpaRepository<UserRegistration, Long> {

    UserRegistration findByEmail(String email);

    void deleteByEmail(String email);

}
问题在于它出现了 "No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call; nested exception is javax.persistence.TransactionRequiredException" 异常。

我可以通过将服务 deleteByEmail(..) 方法标记为事务来解决它,但我就是不明白为什么现在会崩溃。Spring 文档明确指出 "CRUD methods on repository instances are transactional by default." (http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions),但显然这个问题却不是...那么这个声明是否只与 CrudRepository 的成员相关呢? ps:这是针对 Spring Data JPA 1.9.4 的。
1个回答

69

您是正确的。只有CRUD方法(CrudRepository方法)默认被标记为事务性。 如果您正在使用自定义查询方法,则应显式使用@Transactional注释进行标记。

@Repository
public interface UserRegistrationRepository extends JpaRepository<UserRegistration, Long> {

    UserRegistration findByEmail(String email);

    @Transactional
    void deleteByEmail(String email);

}

你还应该了解将存储库接口方法标记而不是服务方法所带来的后果。如果您使用默认的事务传播配置(Propagation.REQUIRED),那么:

存储库中的事务配置将被忽略,因为外部事务配置决定了实际使用的事务配置。

http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions

如果您想了解更��关于如何实现它的信息,请查看默认的CrudRepository / JpaRepository实现 - SimpleJpaRepository(您可能正在使用):

https://github.com/spring-projects/spring-data-jpa/blob/main/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java

这里是有趣的代码行:

@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {

这里还有一些事务性方法:

@Transactional
public void deleteById(ID id) {

@Transactional
public <S extends T> S save(S entity) {

4
在spring-data-jpa:2.0.9中,JpaRepository及其祖先源代码中没有@Transactional注解 - 默认的事务处理似乎是在运行时应用的。另外,请注意,如果您在存储库接口上放置了@Transactional( ... 自定义属性 ... ),它将适用于在接口中声明的所有方法以及子接口中声明的所有方法--但不适用于任何在父接口(JpaRepository)中声明的方法,除非你重新声明它们。 - Andrew Spencer
5
@Transactional 注释被应用于默认的 JpaRepository / CrudRepository 实现:SimpleJpaRepository。请参考此处链接查看详情:https://github.com/spring-projects/spring-data-jpa/blob/master/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java ,您将在该链接中找到所有答案 :) - Maciej Marczuk
感谢您的纠正 - 这不是运行时魔法,只是实现类被注释了。尽管如此,我关于重写的评论仍然准确。 - Andrew Spencer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接