1
我有下面的代碼,即在多個線程中運行entires:春數據 - 並行創建 - 如果 - 不存在導致重複
@Component
public class CreateInstrumentTask {
@Autowired
InstrumentRepository repository; // Spring-data JPA repo interface
@Transactional
public void createInstrument(String instrumentId) {
synchronized(instrumentId.intern()) {
QInstrument $instrument = QInstrument.instrument;
Instrument instrument = repository.findOne($instrument.instrumentId.eq(instrumentId));
if (instrument == null) {
log.info("Thread {} creating instrument {}", Thread.currentThread().getName(), message.getInstrumentId());
instrument = createInstrument(instrumentId); // impl. ommitted
repository.saveAndFlush(instrument);
}
}
}
此註銷:
INFO [] Thread taskExecutor-1 creating instrument ABC
INFO [] Thread taskExecutor-17 creating instrument ABC
org.springframework.integration.MessageHandlingException:
org.springframework.dao.DataIntegrityViolationException: Duplicate entry 'ABC' for key 'instrumentId';
我預計鑑於代碼是而不是instrumentId
,應該防止重複。但是,我猜這是因爲代碼是事務性的,並且事務的邊界在方法上(而不是同步塊),因此在事務持續之前釋放鎖,允許重複。
這必須是一個相當常見的模式(「create-if-not-exists」)。以並行方式執行此操作的正確方法是什麼?
不知道是同步的,一個,因爲它基本上是序列化到這種方法限制了吞吐量和顛覆的多想法獲得一個好主意首先對它進行線程訪問。您是否想過捕獲異常並處理其中的更新情況? – 2013-04-05 11:35:23
@OliverGierke這是一個絕妙的主意 - 我沒有考慮過它,不。處理的序列化是可口的,因爲大部分更新是針對不同的工具的,因此代碼不會鎖定。不過,我會嘗試交換你的方法。感謝您的想法! – 2013-04-06 02:18:47