2013-04-04 55 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); 
    } 
} 
相关问题