我正在研究spring boot和jpa存储库,在处理多线程时遇到了一个问题。
数据库中有500个OfferCode,默认情况下,allocatedFlag设置为null,模型为“ABC”,代码在所有500条记录中都是唯一的。我试图在这里实现的目标是调用register方法来使用OfferCode并将allocatedFlag设置为1。 我在这里遇到的问题是这一行
System.out.println(Thread.currentThread().getName()+" offer code "+offerCode.getCode()+" "+offerCode.getAllocatedFlag());
有时它会打印不同的线程名称但使用相同的代码并且allocatedFlag为null。由于我使用的是同步,我认为理想情况下不应该发生。 如果正确执行了findTop1ByAllocatedFlagIsNullAndModel,一旦返回OfferCode,allocateFlag将被设置为1,然后第二个线程进入它不应该获得与最后一个线程相同的代码。 但是现在我得到了 对于线程A,我得到了例如,
Thread-A 0000-0000-00001 null
Thread-A 0000-0000-00001 1
对于线程B,我得到了例如,
Thread-B 0000-0000-00001 null
Thread-B 0000-0000-00001 1
我认为应该
Thread-B 0000-0000-00002 null
Thread-B 0000-0000-00002 1
所以我不确定我是否正确使用了synchronized或者JpaRepository存在一些问题
我还发现如果我将OfferCodeRepository更改为以下,那么它正在工作。所以有人知道这里有什么问题吗?
@Repository
public interface OfferCodeRepository extends JpaRepository<OfferCode, Integer>{
@Lock(LockModeType.PESSIMISTIC_READ)
Optional<OfferCode> findTop1ByAllocatedFlagIsNullAndModel(String model);
}
我的代码
@Entity
public class OfferCode {
@Id
@GeneratedValue
private int id;
@Version
private int version;
private String model;
private String code;
private String allocatedFlag;
}
@Repository
public interface OfferCodeRepository extends JpaRepository<OfferCode, Integer>{
Optional<OfferCode> findTop1ByAllocatedFlagIsNullAndModel(String model);
}
@Service
public class OfferCodeServiceImpl implements OfferCodeService {
@Autowired
private OfferCodeRepository offerCodeRepository;
@Override
public Optional<OfferCode> findTop1ByAllocatedFlagIsNullAndModel(String model) {
return offerCodeRepository.findTop1ByAllocatedFlagIsNullAndModel(model);
}
@Override
public OfferCode update(OfferCode code) {
return offerCodeRepository.saveAndFlush(code);
}
}
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private OfferCodeService offerCodeService;
@Transactional
public synchronized Product register(Product product) {
if(product!=null){
Optional<OfferCode> optional = offerCodeService.findTop1ByAllocatedFlagIsNullAndModel(product.getModel());
optional.ifPresent(offerCode->{
System.out.println(Thread.currentThread().getName()+" offer code "+offerCode.getCode()+" "+offerCode.getAllocatedFlag());
offerCode.setAllocatedFlag("1");
offerCodeService.update(offerCode);
System.out.println(Thread.currentThread().getName()+" offer code "+offerCode.getCode()+" "+offerCode.getAllocatedFlag());
});
}
return product;
}
}