我有以下问题。我有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;
}
}
祝你好运, 安德烈
答案 0 :(得分:1)
如果你在一个线程中写了多个对象,并且其中一个因为复制而失败,那么你必须弄清楚哪一个是副本,将它从集合中删除,然后重试写它到DB(更改另一个失败)。这需要很多时间。或者,您可以在写入集合之前读取数据库以查看是否存在重复项,并在写入之前删除重复项。如果读取/检查/写入模式不包含在同步块中,则该读取/检查/写入模式存在缺陷,因为其他线程可能在步骤之间写入重复项。修复此问题所需的同步将在每次写入时停止服务器,暂停所有现有线程,可能会损害性能。
相反,每个对象产生一个线程,并在该线程中写入该对象(没有读/检)。大多数对象都会毫无问题地编写,因为大多数对象都不是重复的(假设,但它可能是正确的)。重复的对象将失败并出现异常,此时您可以终止该线程,因为相关工作已经完成。