Transaction and Spring Data JPA
本文档的大主题是 Spring Data JPA,所以自然要来谈谈 Spring Data JPA 和事务的一些关系。
一个重要的点是,从 SimpleJpaRepository
中继承的 CRUD 方法都被默认标记为了 @Transactional
。对于只读操作,@Transactional
的 readOnly
参数被设定为 true
。所有其他方法都使用没有参数的 @Transactional
注解进行标记。
如果需要调整 CRUD 方法的事务性,需要在你自己的 Repository 接口中进行覆盖:
public interface UserRepository extends CrudRepository<User, Long> {
@Override
@Transactional(timeout = 10)
public List<User> findAll();
// Further query method declarations
}
现在,findAll()
方法有了一个 10 秒钟的超时时限,同时去掉了 readOnly
flag。
另外一个调整事务行为的方法是在 Service 中进行:
@Service
public class UserManagementImpl implements UserManagement {
private final UserRepository userRepository;
private final RoleRepository roleRepository;
public UserManagementImpl(UserRepository userRepository,
RoleRepository roleRepository) {
this.userRepository = userRepository;
this.roleRepository = roleRepository;
}
@Transactional
public void addRoleToAllUsers(String roleName) {
Role role = roleRepository.findByName(roleName);
for (User user : userRepository.findAll()) {
user.addRole(role);
userRepository.save(user);
}
}
}
该例使得 addRoleToAllUsers()
方法在事务中运行(参与一个已有事务或者新建一个事务(如果没有正在运行的事务))。这种情况下,Repository 中的事务设定都会被忽略,因为现在外部事务配置决定了真正的设定。
注意:从 JPA 的角度来讲,这里使用 save()
方法是没有必要的,因为 role
是用 Repository 取出的,且处于事务内,所以其被代理,任何对其的改变都会在事务结束后自动提交!但是,这里仍然使用了 save()
方法,主要是为了与 Spring Data 提供的 Repository 抽象保持一致。
自定义方法的事务性:
@Transactional(readOnly = true)
interface UserRepository extends JpaRepository<User, Long> {
List<User> findByLastname(String lastname);
@Transactional
void deleteByEmail(String email);
@Modifying
@Transactional
@Query("delete from User u where u.active = false")
void deleteInactiveUsers();
}
技巧是在 Repository 上标记 @Transactional(readOnly = true)
,然后对 Repository 内部的非只读查询自定义操作再标记 @Transactional
即可。
最后更新于