事務性
`CrudRepository` 例項的方法預設是事務性的。對於讀取操作,事務配置的 `readOnly` 標誌設定為 `true`。所有其他操作都配置了普通的 `@Transactional` 註解,因此應用預設的事務配置。詳情請參閱 SimpleJdbcRepository
的 Javadoc。如果您需要調整 Repository 中某個方法的事務配置,請在您的 Repository 介面中重新宣告該方法,如下所示
interface UserRepository extends CrudRepository<User, Long> {
@Override
@Transactional(timeout = 10)
List<User> findAll();
// Further query method declarations
}
上述配置使 `findAll()` 方法以 10 秒的超時時間執行,並且沒有 `readOnly` 標誌。
另一種改變事務行為的方式是使用通常覆蓋多個 Repository 的 Facade(門面)或服務實現。其目的是為非 CRUD 操作定義事務邊界。以下示例展示瞭如何建立這樣的 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);
}
}
前面的示例使得對 `addRoleToAllUsers(…)` 的呼叫在事務中執行(參與現有事務或在沒有事務執行時建立新事務)。Repository 的事務配置被忽略,因為外部事務配置決定了實際使用的 Repository。請注意,您必須顯式啟用 `<tx:annotation-driven />` 或使用 `@EnableTransactionManagement` 才能使基於註解的 Facade 配置生效。請注意,前面的示例假設您使用元件掃描。
事務性查詢方法
為了使您的查詢方法具有事務性,請在您定義的 Repository 介面上使用 `@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` 標誌設定為 `false`。
強烈建議使查詢方法具有事務性。這些方法可能執行多個查詢以填充實體。如果沒有公共事務,Spring Data JDBC 會在不同的連線中執行查詢。這可能會對連線池造成過度壓力,甚至在多個方法在持有一個連線的同時請求新連線時導致死鎖。 |
透過設定 `readOnly` 標誌來標記只讀查詢是完全合理的。然而,這並不能確保您不會觸發操作資料的查詢(儘管有些資料庫在只讀事務中拒絕 `INSERT` 和 `UPDATE` 語句)。相反,`readOnly` 標誌會作為效能最佳化的提示傳播給底層的 JDBC 驅動程式。 |
JDBC 鎖定
Spring Data JDBC 支援對派生查詢方法進行鎖定。要在 Repository 中的給定派生查詢方法上啟用鎖定,您需要使用 `@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 Dialect 的資料庫,例如,將生成以下查詢
Select * from user u where u.lastname = lastname LOCK IN SHARE MODE