交易性
CrudRepository
實例的方法預設為交易式。對於讀取操作,交易組態 readOnly
旗標設定為 true
。所有其他操作都使用純 @Transactional
註解進行組態,以便套用預設交易組態。如需詳細資訊,請參閱 SimpleJdbcRepository
的 Javadoc。如果您需要調整儲存庫中宣告的其中一個方法的交易組態,請在您的儲存庫介面中重新宣告該方法,如下所示
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
旗標設定為 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 Dialect 的資料庫,這將導致例如以下查詢
Select * from user u where u.lastname = lastname LOCK IN SHARE MODE