多线程 - 插入期间重复的键异常

时间:2014-02-20 20:16:26

标签: java multithreading hibernate spring-data

当我尝试在多线程环境中创建数据时遇到问题。在调用super.create()之前,我检查数据库中是否还没有数据。但我相信线程同时调用方法create(),其中一个失败抛出重复键异常而不是IllegalArgumentException:

    @Transactional(readOnly=false)
    @Override
    public T create(T resource){

      //check if data already exists
      if(this.repository.findById(resource.getId()) != null){
         throw new IllegalArgumentException("Resource already exists");
      }

      //else call create
      return super.create(resource);
    }

是否有任何意义使其有效?该项目使用spring-data-jpa和Hibernate 4.3.1.Final和Oracle数据库

PS:我需要一个更聪明的解决方案,而不仅仅是捕获异常,因为我在更新过程中遇到了同样的问题,如果资源日期比资源日期更新,我必须检查集成日期是否更新资源。数据库中。

我的项目必须在多个节点上运行。

谢谢

3 个答案:

答案 0 :(得分:0)

您可以使用带有同步的双重检查锁定(http://en.wikipedia.org/wiki/Double-checked_locking)来强化您的方法,以确保只有一个创建的对象,而其他线程只是跳过创建。诀窍是检查对象是否存在,然后输入一个synchronized块然后再次检查。

伪代码:

if (noObjectExists()) {
    synchronized {
        if (noObjectExists()) {
            // Create object
        }
    }
}

答案 1 :(得分:0)

如果您确定单resource只有一个resource.id,则可以锁定resource个对象。

@Transactional(readOnly=false)
@Override
public T create(T resource){
    synchronized (resource) {
        //check if data already exists
        if(this.repository.findById(resource.getId()) != null){
            throw new IllegalArgumentException("Resource already exists");
        }

        //else call create
        return super.create(resource);
    }
}

答案 2 :(得分:0)

<强>插入

  • U可以使用AtomicInteger作为
  • 的唯一键

<强>更新用

  • 多线程更新是痛苦的工作之一。您可以使用同步块。但这也是性能开销之一。更新等待不必要的行,即使它与此无关。因此我们可以针对唯一列创建锁定。所以相同的行不会更新两次。同样在Hibernate中,我们可以在同步块中获取对象和更新。