Transactionality

默认情况下,从 CrudRepository 继承的方法从 SimpleJpaRepository 继承事务配置。对于读取操作,事务配置 readOnly 标志被设置为 true。所有其他内容都使用普通 @Transactional 进行配置,以便应用默认事务配置。受事务仓库片段支持的仓库方法从实际片段方法继承事务属性。 如果你需要调整存储库中声明的某个方法的事务配置,请在存储库接口中重新声明该方法,如下所示: .Custom transaction configuration for CRUD

public interface UserRepository extends CrudRepository<User, Long> {

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

  // Further query method declarations
}

这样做会使 findAll() 方法在 10 秒内没有 readOnly 标志的情况下运行。

更改事务行为的另一种方法是使用通常涵盖多个存储库的外观或服务实现。其目的是为非 CRUD 操作定义事务边界。以下示例展示了如何将此类外观用于多个存储库: .Using a facade to define transactions for multiple repository calls

@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 才能使基于注释的外观配置生效。此示例假设你使用了组件扫描。 请注意,从 JPA 的角度来看,对 save 的调用并不是绝对必要的,但为了保持与 Spring Data 提供的存储库抽象的一致性,仍然需要进行该调用。

Transactional query methods

默认情况下,声明的查询方法(包括默认方法)不会应用任何事务配置。要以事务方式运行这些方法,请在定义的存储库接口中使用 @Transactional,如以下示例所示:

Example 1. Using @Transactional at query methods
@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 标志设置为 false 的方式运行。

你可以将事务用于只读查询,并通过设置 readOnly 标志将其标记为只读查询。但是,这样做不会作为检查,以确保你不会触发操作查询(尽管一些数据库拒绝只读事务中的 INSERTUPDATE 语句)。而是将 readOnly 标志作为提示传播到基础 JDBC 驱动程序,以进行性能优化。此外,Spring 对底层 JPA 提供程序执行了一些优化。例如,当与 Hibernate 一起使用时,在你将事务配置为 readOnly 时,刷新模式将被设置为 NEVER,这将导致 Hibernate 跳过脏检查(对于大型对象树而言是一个显着的改进)。