java - 数据库中Spring中的写锁实体

标签 java spring locking

我在处理他的子实体时需要写锁定父实体,以便不允许修改(或听到)父实体。 我需要使用 Spring 并直接从数据库执行锁定(以避免应用程序在集群中执行时出现问题)。

最佳答案

为了实现您正在寻找的策略,您需要触发 SELECT FOR UPDATE父行上的 SQL 查询(例如,SELECT * FROM parent WHERE id = ? FOR UPDATE。这会锁定由 SELECT 查询获取的行。

General strategy

  1. 开始交易。
  2. SELECT FOR UPDATE 加载父行.
  3. 更新 child 。
  4. 拯救 child 。
  5. 提交交易。这将保存子项并释放对父行的锁定。

您可以使用 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 查询类(class)。 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);
}

会完成这项工作。


您应该注意的一件事是,如果此操作同时被调用太多次,您将遇到超时并且也可能是死锁,因为行正在被独占锁定。牢记以下几点会让您受益:

  1. 仅将锁定保留很短的时间,可能是在处理的最后阶段,确保预先执行任何验证等。这将确保快速释放锁。
  2. 对并发用户进行测试,了解超时和死锁发生的频率。如果您看到超时和死锁并且不希望用户重试,您可以使用 Spring Retry 项目提供的功能来重试方法。

关于java - 数据库中Spring中的写锁实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35786815/

相关文章:

spring - thymeleaf/ Spring : How to check if a message property exists

java - 使用 3 个 PetersonLock 的数组来同步 4 个进程

java - for循环这是什么意思?

具有 Guice 注入(inject)字段和非注入(inject)字段的 Java 构造函数

java - 在多个 WAR 中访问库的通用接口(interface)——这在 jboss 中可能吗?

Spring 启动 : Not to use TLSv1. 0

Java Https 默认重试机制

java - Spring 中的内部 bean 是什么?

c# - 实现线程安全的队列或列表时,返回Count前是否需要加锁?

postgresql 删除陈旧的锁