2016-03-04 54 views
1

我需要寫鎖定一個父實體,而我正在與他的子實體,以不允許修改(或earse)的父母。 我需要使用Spring來執行此操作,並直接從數據庫執行鎖定(以避免在集羣中執行應用程序時出現問題)。從數據庫中寫入鎖實體在彈簧

回答

9

爲了實現你正在尋找的策略,你將需要火父排SELECT FOR UPDATE SQL查詢(例如,SELECT * FROM parent WHERE id = ? FOR UPDATE,這獲得由SELECT查詢獲取的行上的鎖。

總體戰略

  1. 開始事務。
  2. 裝入父行與SELECT FOR UPDATE
  3. 更新孩子。
  4. 保存孩子。
  5. 提交交易。這將保存子項並釋放父行上的鎖。

您可以使用Spring事務來強制執行事務邊界。像下面的內容將工作:

class SomeService { 
    @Transactional 
    public ... someMethod(...) { 
    // Load the parent row using SELECT FOR UPDATE. 

    // Save children. 
    } 
} 

@Transactional將申請事務語義各地調用someMethod。請注意,該方法必須爲public才能運作@Transactional


執行一個SELECT FOR UPDATE取決於你究竟是如何訪問數據庫 - 春天JDBC,ORM春天,春天JPA的數據,等等。這裏是你將如何使用這些庫來實現這一目標:

春天JDBC

您可以使用JdbcTemplate類簡單地執行SELECT FOR UPDATE查詢。 jdbcTemplate.execute("SELECT * FROM parent WHERE row = ? FOR UPDATE")應該工作。

春ORM

你將不得不使用特定的ORM模板類強制執行鎖定模式。例如,使用Hibernate4 HibernateTemplate可以使用hibernateTemplate.get(Class<T> entityType, Serializable id, LockMode lock)

春數據JPA

您可以標註信息庫法@Lock(LockModeType.PESSIMISTIC_WRITE)執行查詢時強制執行悲觀鎖。例如

interface ParentRepository extends CrudRepository<Parent, Long> { 
    @Lock(LockModeType.PESSIMISTIC_WRITE) 
    Parent findOne(Long id); 
} 

會完成這項工作。你應該小心


的一件事是,如果這種操作稱爲併發的次數太多,你會體驗到超時和可能出現的死鎖,因爲行被完全鎖定。記住以下事項會使您受益:

  1. 保持鎖只有很短的時間,可能是在處理的最後階段,確保任何驗證等都是預先執行的。這將確保鎖被快速釋放。
  2. 對併發用戶進行測試,並瞭解出現超時和死鎖的頻率。如果您看到超時和死鎖,並且不希望用戶重試,則可以使用Spring Retry項目提供的功能重試方法。