Concurrency Spring数据JPA-实体的并发访问
我想确保只有1个线程可以访问我的服务函数中的实体。怎么做 示例:我希望安全地减少计数:即使多个线程执行OrderService.remove(产品),我也不希望使用相同的计数器值进行2次DB更新 在多线程环境中,2个线程可以同时执行此函数,它们可以读取相同的计数器值,因此使用相同的减少值更新数据库。这是不可取的 产品:Concurrency Spring数据JPA-实体的并发访问,concurrency,transactions,spring-data,locking,spring-data-jpa,Concurrency,Transactions,Spring Data,Locking,Spring Data Jpa,我想确保只有1个线程可以访问我的服务函数中的实体。怎么做 示例:我希望安全地减少计数:即使多个线程执行OrderService.remove(产品),我也不希望使用相同的计数器值进行2次DB更新 在多线程环境中,2个线程可以同时执行此函数,它们可以读取相同的计数器值,因此使用相同的减少值更新数据库。这是不可取的 产品: @Entity public class Product { @Id @GeneratedValue private UUID id; pri
@Entity
public class Product {
@Id
@GeneratedValue
private UUID id;
private Integer count;
...
产品服务:
@Service
@Transactional
public class ProductService {
public void remove(UUID productId) {
final Product product = productRepository.findById(productId);
// TODO how to lock product, so no other thread can modify it before this operation is committed?
final Integer currentCount = product.getCount();
product.setCount(currentCount-1);
}
}
您希望将(…)
方法作为事务工作(这样就不会使用此方法对数据库进行并发更新)。为此,应将该方法标记为@Transactional
只要可串行化保证并发事务的效果等同于它们的串行(即顺序)执行,就可以将隔离级别显式设置为
隔离。可串行化
就足够了
@Transactional(isolation = Isolation.SERIALIZABLE)
public void remove(UUID productId) {
...
}
如果在处理事务时需要更多高级逻辑,可以使用较低的隔离级别并重试策略:@Retryable(StaleStateException.class)
有关详细信息,请参见。能否澄清您的问题?您希望对“Product.count”字段进行线程安全修改,还是希望进行事务性数据库更新?我更新了我的问题。然后更新了答案。如果我没有指定隔离级别并且没有设置重试策略,则在发生冲突的事务时会发生什么情况?只有一个事务成功吗?数据库将为您执行所有锁定。如果两个事务(您的
remove()
方法)试图访问相同的数据,其中一个事务将被迫等待,直到另一个事务完成。这两个事务将按第一个事务执行,另一个事务在第一个事务完成后到达。我知道如果设置了隔离=隔离.SERLIALIZE,情况就是这样,但是如果隔离级别更宽松,会发生什么?(例如,默认值)使用其他隔离级别,您将获得它们为您提供的确切保证。例如,您可以看到本教程:默认隔离级别的行为因数据库而异。例如,在Postgres中,它被读取为提交: