【发布时间】:2016-03-04 02:16:08
【问题描述】:
当我使用他的子实体时,我需要对父实体进行写锁定,以便不允许修改(或监听)父实体。 我需要使用 Spring 执行此操作并直接从数据库执行锁定(以避免在集群中执行应用程序时出现问题)。
【问题讨论】:
当我使用他的子实体时,我需要对父实体进行写锁定,以便不允许修改(或监听)父实体。 我需要使用 Spring 执行此操作并直接从数据库执行锁定(以避免在集群中执行应用程序时出现问题)。
【问题讨论】:
为了实现您正在寻找的策略,您需要在父行上触发一个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
您可以使用JdbcTemplate 类简单地执行SELECT FOR UPDATE 查询。 jdbcTemplate.execute("SELECT * FROM parent WHERE row = ? FOR UPDATE") 应该可以工作。
Spring 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);
}
会做的。
您应该注意的一件事是,如果此操作同时调用太多次,您将遇到超时并且还可能出现死锁,因为行被排他地锁定。牢记以下几点将使您受益:
【讨论】: