事务性

默认情况下,实例的方法为事务性。 对于读取操作,事务配置标志设置为 。 所有其他 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

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