【问题标题】:Write-lock entity in Spring from database来自数据库的Spring中的写锁定实体
【发布时间】:2016-03-04 02:16:08
【问题描述】:

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

【问题讨论】:

    标签: java spring locking


    【解决方案1】:

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

    总体战略

    1. 开始交易。
    2. 使用SELECT FOR UPDATE 加载父行。
    3. 更新孩子。
    4. 救救孩子们。
    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

    您可以使用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);
    }
    

    会做的。


    您应该注意的一件事是,如果此操作同时调用太多次,您将遇到超时并且还可能出现死锁,因为行被排他地锁定。牢记以下几点将使您受益:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-07
      • 2011-08-12
      • 2019-04-24
      • 2019-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多