此版本仍在开发中,尚未被视为稳定版。如需使用最新的稳定版本,请访问 Spring Data JPA 4.0.4spring-doc.cadn.net.cn

事务性

默认情况下,从 CrudRepository 继承的方法会从 SimpleJpaRepository 继承事务配置。 对于读操作,事务配置 readOnly 标志被设置为 true。 其他所有方法均配置为普通的 @Transactional,以便应用默认事务配置。 由事务性存储库片段支持的存储库方法会从实际的片段方法继承事务属性。spring-doc.cadn.net.cn

如果你需要调整在仓库中声明的某个方法的事务配置,请在你的仓库接口中重新声明该方法,如下所示:spring-doc.cadn.net.cn

示例 1. CRUD 的自定义事务配置
public interface UserRepository extends CrudRepository<User, Long> {

  @Override
  @Transactional(timeout = 10)
  public List<User> findAll();

  // Further query method declarations
}

这样做会使 findAll() 方法以 10 秒的超时时间运行,并且不启用 readOnly 标志。spring-doc.cadn.net.cn

另一种修改事务行为的方式是使用一个门面(facade)或服务实现,它通常涵盖多个仓库(repository)。其目的是为非 CRUD 操作定义事务边界。以下示例展示了如何对多个仓库使用此类门面:spring-doc.cadn.net.cn

示例2. 使用外观(Facade)为多个仓库调用定义事务
@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(…) 的调用在事务中运行(参与现有事务,或在没有事务运行时创建一个新事务)。此时,仓库上的事务配置将被忽略,因为实际使用的事务由外部的事务配置决定。请注意,您必须激活 <tx:annotation-driven /> 或显式使用 @EnableTransactionManagement,才能使基于注解的外观(facade)配置生效。 本示例假定您使用了组件扫描。spring-doc.cadn.net.cn

请注意,从 JPA 的角度来看,调用 save 并非严格必要,但为了与 Spring Data 提供的仓库抽象保持一致,仍应保留该调用。spring-doc.cadn.net.cn

事务性查询方法

声明的查询方法(包括默认方法)默认不会应用任何事务配置。 若要以事务方式运行这些方法,请在您定义的仓库接口上使用 @Transactional 注解,如下例所示:spring-doc.cadn.net.cn

示例 3. 在查询方法上使用 @Transactional
@Transactional(readOnly = true)
interface UserRepository extends JpaRepository<User, Long> {

  List<User> findByLastname(String lastname);

  @Modifying
  @Transactional
  @Query("delete from User u where u.active = false")
  void deleteInactiveUsers();
}

通常,你希望将 readOnly 标志设置为 true,因为大多数查询方法仅读取数据。与此不同的是,deleteInactiveUsers() 方法使用了 @Modifying 注解,并覆盖了事务配置。因此,该方法运行时 readOnly 标志被设置为 falsespring-doc.cadn.net.cn

您可以将事务用于只读查询,并通过设置 readOnly 标志将其标记为只读。然而,这样做并不会检查您是否触发了修改数据的查询(尽管某些数据库会在只读事务中拒绝 INSERTUPDATE 语句)。相反,readOnly 标志会作为提示传递给底层的 JDBC 驱动程序,以进行性能优化。此外,Spring 还会对底层的 JPA 提供商执行一些优化。例如,当与 Hibernate 一起使用时,如果您将事务配置为 NEVER,则刷新模式会被设为 readOnly,这会使 Hibernate 跳过脏数据检查(在大型对象树上可带来显著的性能提升)。spring-doc.cadn.net.cn

虽然示例中讨论了在仓库(repository)上使用 @Transactional,但我们通常建议在开始一个工作单元时就声明事务边界,以确保适当的一致性和所需的事务参与行为。spring-doc.cadn.net.cn