我想确保只有一个线程可以访问我的服务功能中的实体。怎么做?
示例:我想安全地减少计数:即使多个线程执行OrderService.remove(Product),我也不希望2个DB更新具有相同的计数器值。
在多线程环境中,2个线程可以同时执行此功能,它们可以读取相同的计数器值,因此使用相同的减少值更新DB。这是不可取的。
产品:
@Entity
public class Product {
@Id
@GeneratedValue
private UUID id;
private Integer count;
...
ProductService:
@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);
}
}
答案 0 :(得分:1)
您希望remove(..)
方法工作作为交易(因此,使用此方法无法对数据库进行并发更新) 。为此,您应将方法标记为@Transactional
只要可序列化保证并发事务的影响等同于它们的串行(即顺序)执行,将显式隔离级别明确设置为Isolation.SERIALIZABLE
就足够了。
@Transactional(isolation = Isolation.SERIALIZABLE)
public void remove(UUID productId) {
...
}
如果在处理交易时需要更多高级逻辑,则可以使用较低的隔离级别并重试策略:@Retryable(StaleStateException.class)
。
有关详细信息,请参阅https://github.com/spring-projects/spring-retry。