Hibernate:从不同的线程插入具有唯一约束的对象

时间:2014-07-15 19:06:46

标签: java multithreading hibernate concurrency

我有以下问题。我有10个线程,它们创建插入数据库的对象。每个Thread都有一个ThreadLocal和它自己的会话。创建后,所有对象都会一起插入。这些对象有一个标记为唯一的列。但是,我遇到的问题是,两个不同的线程可能会创建相同的对象。需要此行为,但我不知道如何将它们插入到我的数据库中。

目前,每个线程都会查询插入数据库中的所有对象,检查查询对象是否存在,并将不存在的对象插入数据库。但是,由于可能发生对象在所有对象的查询中不存在,因此当我插入对象并且它们已被另一个Thread添加时,我得到 ConstraintViolationException 。但是,对每个对象执行数据库(或缓存)查询都会导致性能下降,因为我们尝试每个线程和分钟添加1000个对象。如果我尝试在每次插入后刷新数据库,那么我会收到以下错误:尝试获取锁定时发现死锁;尝试重新启动交易

所以我的问题是:如何插入具有来自不同线程的唯一约束的对象。

//编辑:目前我正在使用Hibernate和MYSQL InnoDB

// Edit2:最后,我用来编写单个项目的代码。

public class ItemWriterRunnable implements Callable<Object> {

    private final ThreadLocal<Session> session = new ThreadLocal<Session>();

    private Item item;

    public ItemWriterRunnable(Item item) {
        super();
        this.item= item;
    }

    protected Session currentSession() {
        Session s = this.session.get();
        // Open a new Session, if this thread has none yet
        if (s == null || !s.isOpen()) {
            s = HibernateUtils.getSessionFactory().openSession();
            // Store it in the ThreadLocal variable
            this.session.set(s);
        }
        return s;
    }

    @Override
    public Object call() throws Exception {
        Session currentSession = currentSession();
        try {
            currentSession.beginTransaction();
            currentSession.save(this.item);
            currentSession.getTransaction().commit();
        } catch (ConstraintViolationException e) {
            currentSession.getTransaction().rollback();
        } catch (RuntimeException e) {
            currentSession.getTransaction().rollback();
        } finally {
            currentSession.close();
            currentSession = null;
            this.session.remove();
        }
        return null;
    }
}

祝你好运, 安德烈

1 个答案:

答案 0 :(得分:1)

如果你在一个线程中写了多个对象,并且其中一个因为复制而失败,那么你必须弄清楚哪一个是副本,将它从集合中删除,然后重试写它到DB(更改另一个失败)。这需要很多时间。或者,您可以在写入集合之前读取数据库以查看是否存在重复项,并在写入之前删除重复项。如果读取/检查/写入模式不包含在同步块中,则该读取/检查/写入模式存在缺陷,因为其他线程可能在步骤之间写入重复项。修复此问题所需的同步将在每次写入时停止服务器,暂停所有现有线程,可能会损害性能。

相反,每个对象产生一个线程,并在该线程中写入该对象(没有读/检)。大多数对象都会毫无问题地编写,因为大多数对象都不是重复的(假设,但它可能是正确的)。重复的对象将失败并出现异常,此时您可以终止该线程,因为相关工作已经完成。