Java 处理数据库约束hibernate

Java 处理数据库约束hibernate,java,hibernate,transactions,batch-processing,spring-transactions,Java,Hibernate,Transactions,Batch Processing,Spring Transactions,我的项目使用hibernate和spring事务管理器,我的数据库是postgres(可能与此无关) 我试图读取大的xml文件,并用这些文件构造对象(对象不大,但数量很大),然后将它们插入数据库 如果我的一个对象偶然违反了数据库约束,整个过程就会停止。如何跳过那些违反数据库约束的内容?或者将他们的id或其他信息记录到日志文件中 问题更新: 我一直在浏览,发现对于批量插入,最好使用无状态会话,但我仍然会遇到同样的问题和插入停止: May 26, 2012 4:45:47 PM org.hibern

我的项目使用hibernate和spring事务管理器,我的数据库是postgres(可能与此无关)

我试图读取大的xml文件,并用这些文件构造对象(对象不大,但数量很大),然后将它们插入数据库

如果我的一个对象偶然违反了数据库约束,整个过程就会停止。如何跳过那些违反数据库约束的内容?或者将他们的id或其他信息记录到日志文件中

问题更新:

我一直在浏览,发现对于批量插入,最好使用无状态会话,但我仍然会遇到同样的问题和插入停止:

May 26, 2012 4:45:47 PM org.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: ERROR: duplicate key value violates unique constraint "UN_FK"
  Detail: Key (fid)=(H1) already exists.
以下是我用于解析xml和插入db的代码的相关部分,为了简单起见,假设我正在插入电影:

//class field
@Autowired
private SessionFactory sessionFactory;

@Override
public void startDocument() throws SAXException {
    session = sessionFactory.getCurrentSession();
}

@Override
public void endElement(String uri, String localName, String qName) throws SAXException  {
if (qName.equalsIgnoreCase("FILM")) {
        movie.setCategory(category);
        movie.setAdded(new Date());
        session.insert(movie);
    }
}
我在应用程序ctx
hibernate.jdbc.batch\u size
中将此属性设置为100。是否真的有必要在插入之前进行选择以避免这种情况

更新2:

如果我使用
无状态会话
而不是会话,我会得到大约20个插入,然后处理会无限期地停止,没有任何异常或任何事情

我假设数字20是因为我与tomcat共享连接,并且拥有
maxActive=“20”

赏金更新:


我真的很想看到有人提供解决方案(如果可能的话,没有防御性的选择)。使用无状态会话或仅使用会话。

大多数类型的约束,例如如果列可为空或具有最大宽度,则可以使用检查。在尝试持久化对象之前,只需手动执行该对象上的验证


对于某些事物,特别是独特的约束,你需要执行一个“防御”选择,看看是否存在冲突,或者保持一个内存中已经插入的值集。

< P>从XML文件插入大量对象,你应该考虑使用Spring批处理。 参数skip limit允许您在停止批处理过程之前告知xml中可能有多少错误行。 同时检查跳过策略和可跳过异常;请参阅Spring文档中的

如果您不想使用spring批处理,只需使用一个简单的try-catch,它将允许您的过程一直持续到最后。

我认为在插入前进行防御性选择是正确的方法

可以考虑在每个插入之前使用A,如果引发异常,则回滚到保存点。创建保存点会带来性能开销。完成后需要释放保存点


请参阅或如果您有权访问JDBC连接池和

为什么您认为这一切都必须是一个大事务?你所描述的一切事实上都暗示着你在这里有很多交易。对于“出错”的对象,只需退出该实体并回滚事务。如果“FILM”元素定义了一个对象图,那么它会变得更复杂一些,但想法是一样的。

我认为不可能完全验证某个东西,从而保证插入成功。在某些情况下,无论您做什么,其他人都可以在验证和插入之间向数据库中插入某些内容,从而导致违反约束


在大多数情况下,我只建议像处理其他异常一样处理异常。

虽然这是一个老问题,但我最近遇到了类似的情况,下面是我所做的

我也使用了无状态会话,但以下是我的不同做法。我发布了一个session.insert,由于约束冲突,该session.insert要么成功,要么失败。在约束冲突发生时,将抛出一个ConstraintViolationException,捕捉它将为您提供一个插入失败的对象,对失败的对象执行您想要执行的操作。与事务一起,每次插入都使用保存点(保存点更便宜,不会对性能造成太大影响),因此,当事务因某些问题而失败时,提交将一直执行到最后一个保存点(在catch子句中)

我的代码如下所示:

try {
  session.connection().setSavePoint("lastSaved");
  session.insert(obj);
}
catch(ConstraintViolationException) {
  log.error(obj.getUserId());
  ....
}
tx.commit();
....
catch(TransactionException e) {
  tx.rollback();
}

一个简单的try-catch语句不行。一旦Hibernate抛出异常,会话状态就不一致,必须回滚事务,并关闭会话。此外,只有在错误记录被持久化很久之后,才会在刷新时抛出异常。这就是为什么建议在此类情况下使用无状态Hibernate会话的原因。它将防止不一致状态,并减少内存消耗(或者您不必逐出已经处理过的实体)