2013-04-04 32 views
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」)。以並行方式執行此操作的正確方法是什麼?

+0

不知道是同步的,一個,因爲它基本上是序列化到這種方法限制了吞吐量和顛覆的多想法獲得一個好主意首先對它進行線程訪問。您是否想過捕獲異常並處理其中的更新情況? – 2013-04-05 11:35:23

+0

@OliverGierke這是一個絕妙的主意 - 我沒有考慮過它,不。處理的序列化是可口的,因爲大部分更新是針對不同的工具的,因此代碼不會鎖定。不過,我會嘗試交換你的方法。感謝您的想法! – 2013-04-06 02:18:47

回答

1

我結束了重構的方法轉移事務邊界:

public void createInstrument(String instrumentId) { 
    synchronized(instrumentId.intern()) { 
     persistInstrument(instrumentId); 
    } 
} 

@Transactional 
protected void persistInstrument(String instrumentId) { 
    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); 
    } 
} 
相關問題