默认情况下,实例的方法为事务性。 对于读取操作,事务配置标志设置为 。 所有其他 Comments 都配置了普通 Comments,以便应用默认事务配置。 有关详细信息,请参见 SimpleJdbcRepository 的 Javadoc。 如果需要调整存储库中声明的方法之一的事务配置,请在存储库接口中重新声明该方法,如下所示:CrudRepositoryreadOnlytrue@Transactionalspring-doc.cn

CRUD 的自定义交易配置
interface UserRepository extends CrudRepository<User, Long> {

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

  // Further query method declarations
}

上述情况会导致该方法以 10 秒的超时运行,并且没有标志。findAll()readOnlyspring-doc.cn

更改事务行为的另一种方法是使用通常涵盖多个存储库的 Fade 或服务实现。 其目的是定义非 CRUD 操作的事务边界。 以下示例演示如何创建此类 Facade:spring-doc.cn

使用 Facade 定义多个存储库调用的事务
@Service
public class UserManagementImpl implements UserManagement {

  private final UserRepository userRepository;
  private final RoleRepository roleRepository;

  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);
    }
}

前面的示例导致调用在事务内运行(参与现有事务,如果没有运行,则创建新事务)。 存储库的事务配置被忽略,因为外部事务配置决定了要使用的实际存储库。 请注意,您必须显式激活或使用才能获得基于 Comments 的 Facade 配置。 请注意,前面的示例假定您使用组件扫描。addRoleToAllUsers(…)<tx:annotation-driven />@EnableTransactionManagementspring-doc.cn

事务查询方法

要使查询方法具有事务性,请在您定义的存储库界面中使用,如下例所示:@Transactionalspring-doc.cn

在 Query 方法中使用 @Transactional
@Transactional(readOnly = true)
interface UserRepository extends CrudRepository<User, Long> {

  List<User> findByLastname(String lastname);

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

通常,您希望将标志设置为 true,因为大多数查询方法只读取数据。 与此相反,使用 annotation 并覆盖事务配置。 因此,该方法将标志设置为 。readOnlydeleteInactiveUsers()@ModifyingreadOnlyfalsespring-doc.cn

强烈建议将查询方法设置为事务性。 这些方法可能会执行多个查询以填充实体。 如果没有公共事务,Spring Data JDBC 会在不同的连接中执行查询。 这可能会给连接池带来过大的压力,甚至可能导致在多个方法请求新连接而保留一个方法时出现死锁。
通过设置标志将只读查询标记为这样绝对是合理的。 但是,这并不能作为检查您不会触发操纵查询(尽管某些数据库在只读事务中拒绝 and 语句)。 相反,该标志将作为提示传播到底层 JDBC 驱动程序,以实现性能优化。readOnlyINSERTUPDATEreadOnly
强烈建议将查询方法设置为事务性。 这些方法可能会执行多个查询以填充实体。 如果没有公共事务,Spring Data JDBC 会在不同的连接中执行查询。 这可能会给连接池带来过大的压力,甚至可能导致在多个方法请求新连接而保留一个方法时出现死锁。
通过设置标志将只读查询标记为这样绝对是合理的。 但是,这并不能作为检查您不会触发操纵查询(尽管某些数据库在只读事务中拒绝 and 语句)。 相反,该标志将作为提示传播到底层 JDBC 驱动程序,以实现性能优化。readOnlyINSERTUPDATEreadOnly

JDBC 锁定

Spring Data JDBC 支持对派生查询方法的锁定。 要在存储库中启用对给定派生查询方法的锁定,请使用 . type 的 required 值提供两个值:保证您正在读取的数据不会被修改,以及获取用于修改数据的锁。 某些数据库不进行这种区分。 在这种情况下,两种模式都等效于 。@LockLockModePESSIMISTIC_READPESSIMISTIC_WRITEPESSIMISTIC_WRITEspring-doc.cn

对派生查询方法使用 @Lock
interface UserRepository extends CrudRepository<User, Long> {

  @Lock(LockMode.PESSIMISTIC_READ)
  List<User> findByLastname(String lastname);
}

正如你在上面看到的,该方法将使用悲观读锁执行。 如果将数据库与 MySQL Dialect 一起使用,则将导致例如以下查询:findByLastname(String lastname)spring-doc.cn

生成的 MySQL 方言的 Sql 查询
Select * from user u where u.lastname = lastname LOCK IN SHARE MODE