交易性

CrudRepository 實例的方法預設為交易式。對於讀取操作,交易組態 readOnly 旗標設定為 true。所有其他操作都使用純 @Transactional 註解進行組態,以便套用預設交易組態。如需詳細資訊,請參閱 SimpleJdbcRepository 的 Javadoc。如果您需要調整儲存庫中宣告的其中一個方法的交易組態,請在您的儲存庫介面中重新宣告該方法,如下所示

CRUD 的自訂交易組態
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
@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 旗標)絕對是合理的。但是,這並不能作為您不會觸發操作查詢的檢查(儘管某些資料庫會拒絕唯讀交易內的 INSERTUPDATE 陳述式)。相反地,readOnly 旗標會作為提示傳播到基礎 JDBC 驅動程式,以進行效能最佳化。

JDBC 鎖定

Spring Data JDBC 支援衍生查詢方法的鎖定。若要在儲存庫內的給定衍生查詢方法上啟用鎖定,您可以使用 @Lock 註解它。LockMode 類型的必要值提供兩個值:PESSIMISTIC_READ,它保證您正在讀取的資料不會被修改,以及 PESSIMISTIC_WRITE,它取得鎖定以修改資料。某些資料庫不會區分這兩者。在這些情況下,兩種模式都相當於 PESSIMISTIC_WRITE

在衍生查詢方法上使用 @Lock
interface UserRepository extends CrudRepository<User, Long> {

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

如您在上方看到的,findByLastname(String lastname) 方法將以悲觀讀取鎖定執行。如果您使用的是具有 MySQL Dialect 的資料庫,這將導致例如以下查詢

MySQL Dialect 的結果 Sql 查詢
Select * from user u where u.lastname = lastname LOCK IN SHARE MODE