当我正在使用他的子实体时,我需要对父实体进行写锁定,以便不允许修改(或者简化)父实体。 我需要使用Spring并直接从数据库执行锁定(以避免在集群中执行应用程序时出现问题)。
答案 0 :(得分:13)
为了实现您正在寻找的策略,您需要在父行上触发SELECT FOR UPDATE
SQL查询(例如,SELECT * FROM parent WHERE id = ? FOR UPDATE
。这将获取对所提取的行的锁定SELECT
查询。
一般策略
SELECT FOR UPDATE
加载父行。您可以使用Spring Transactions来强制执行事务边界。以下内容将起作用:
class SomeService {
@Transactional
public ... someMethod(...) {
// Load the parent row using SELECT FOR UPDATE.
// Save children.
}
}
@Transactional
将围绕对someMethod
的调用应用事务语义。请注意,public
的方法必须为@Transactional
才能生效。
执行SELECT FOR UPDATE
取决于您访问数据库的准确程度 - Spring JDBC,Spring ORM,Spring Data JPA等。以下是使用这些库实现此目的的方法:
Spring JDBC
您只需使用SELECT FOR UPDATE
类执行JdbcTemplate
查询即可。 jdbcTemplate.execute("SELECT * FROM parent WHERE row = ? FOR UPDATE")
应该有用。
春季ORM
您必须使用特定于ORM的模板类来强制执行锁定模式。例如,使用Hibernate4 HibernateTemplate
,您可以使用hibernateTemplate.get(Class<T> entityType, Serializable id, LockMode lock)
。
Spring Data JPA
您可以使用@Lock(LockModeType.PESSIMISTIC_WRITE)
注释存储库方法,以在执行查询时强制执行悲观锁定。例如
interface ParentRepository extends CrudRepository<Parent, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
Parent findOne(Long id);
}
将完成这项工作。
您应该注意的一件事是,如果同时调用此操作太多次,您将遇到超时并且可能也会出现死锁,因为行被排他性地锁定。您将从以下方面受益: