此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Data Relational 3.5.2! |
交易性
的方法CrudRepository
默认情况下,实例是事务性的。
对于读取作,事务配置readOnly
标志设置为true
.
所有其他配置都配置了普通@Transactional
注释,以便应用默认事务配置。
有关详细信息,请参阅SimpleJdbcRepository
.
如果需要调整存储库中声明的方法之一的事务配置,请在存储库接口中重新声明该方法,如下所示:
interface UserRepository extends CrudRepository<User, Long> {
@Override
@Transactional(timeout = 10)
List<User> findAll();
// Further query method declarations
}
上述原因导致findAll()
方法以 10 秒的超时运行,并且没有readOnly
旗。
改变事务行为的另一种方法是使用通常涵盖多个存储库的外观或服务实现。 其目的是为非 CRUD作定义事务边界。 以下示例显示了如何创建这样的立面:
@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);
}
}
}
前面的示例导致调用addRoleToAllUsers(…)
在事务中运行(参与现有事务或如果尚未运行则创建新事务)。
存储库的事务配置被忽略,因为外部事务配置确定了要使用的实际存储库。
请注意,您必须显式激活<tx:annotation-driven />
或使用@EnableTransactionManagement
为外墙工作提供基于注释的配置。
请注意,前面的示例假定您使用组件扫描。
事务查询方法
要让您的查询方法是事务性的,请使用@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();
}
通常,您需要readOnly
标志设置为 true,因为大多数查询方法只读取数据。
与此相反,deleteInactiveUsers()
使用@Modifying
注释并覆盖事务配置。
因此,该方法是使用readOnly
flag 设置为false
.
强烈建议将查询方法设为事务性。 这些方法可能会执行多个查询以填充实体。 如果没有公共事务,Spring Data JDBC 会在不同的连接中执行查询。 这可能会给连接池带来过大的压力,甚至可能导致当多个方法请求新连接同时保留一个连接时导致死锁。 |
通过设置readOnly 旗。
但是,这不会作为检查您是否不会触发作查询(尽管某些数据库拒绝INSERT 和UPDATE 语句)。
相反,该readOnly 标志作为提示传播到底层 JDBC 驱动程序以进行性能优化。 |
JDBC 锁定
Spring Data JDBC 支持锁定派生查询方法。
要在存储库中启用对给定派生查询方法的锁定,请使用@Lock
.
类型LockMode
提供两个值:PESSIMISTIC_READ
这保证您正在读取的数据不会被修改,并且PESSIMISTIC_WRITE
它获得一个锁来修改数据。
有些数据库没有做出这种区分。
在这种情况下,两种模式都等同于PESSIMISTIC_WRITE
.
interface UserRepository extends CrudRepository<User, Long> {
@Lock(LockMode.PESSIMISTIC_READ)
List<User> findByLastname(String lastname);
}
如上所示,该方法findByLastname(String lastname)
将使用悲观读锁执行。
如果您将数据库与 MySQL 方言一起使用,则将导致以下查询:
Select * from user u where u.lastname = lastname LOCK IN SHARE MODE
@Lock 目前不支持基于字符串的查询。
使用@Query ,将忽略@Lock ,
用@Lock on 基于字符串的查询将导致日志中出现警告。
未来的版本将抛出异常。 |