Hibernate 在批插入中,当一行中发生错误时,如何继续插入其他行

Hibernate 在批插入中,当一行中发生错误时,如何继续插入其他行,hibernate,batch-processing,Hibernate,Batch Processing,在我的代码中,我正在执行批插入。例如,我有五行要插入,其中一行在插入时失败。然后休眠以防止插入所有行。 在本例中,我想插入其他四条不包含错误的记录。这在Hibernate中可能吗? 以下是我的代码的简化版本 void save() { Session session1 = HibernateUtil.getSessionFactory().openSession(); Transaction transaction = session1.beginTransaction(); fo

在我的代码中,我正在执行批插入。例如,我有五行要插入,其中一行在插入时失败。然后休眠以防止插入所有行。
在本例中,我想插入其他四条不包含错误的记录。这在Hibernate中可能吗?
以下是我的代码的简化版本

void save() {
  Session session1 = HibernateUtil.getSessionFactory().openSession();
  Transaction transaction = session1.beginTransaction();

  for (int i = 0; i < 5; i++) {
    BatchSizeConf r = new BatchSizeConf();//This is my entity
    r.setId(i);
    r.setDispatchType("Disp");
    r.setBatchSize(500);
    Serializable z = session1.save(r);
    System.out.println(z);//prints ids
  }

  session1.flush();
  session1.clear();
  session1.getTransaction().commit();
  session1.close();
}
void save(){
会话session1=HibernateUtil.getSessionFactory().openSession();
事务处理=会话1.beginTransaction();
对于(int i=0;i<5;i++){
BatchSizeConf r=new BatchSizeConf();//这是我的实体
r、 setId(i);
r、 setDispatchType(“Disp”);
r、 尺寸(500);
Serializable z=session1.save(r);
System.out.println(z);//打印ID
}
session1.flush();
会话1.clear();
session1.getTransaction().commit();
session1.close();
}
编辑
根据下面的答案,我修改了代码并解决了主要问题。现在我的代码是这样的

void save() {
  for (int i = 0; i < 5; i++) {
    Session session1 = HibernateUtil.getSessionFactory().openSession();
    Transaction transaction = session1.beginTransaction();

    BatchSizeConf r = new BatchSizeConf();//This is my entity
    r.setId(i);
    r.setDispatchType("Disp");
    r.setBatchSize(500);

    try {
      session1.save(r);
      transaction.commit();
    } catch (HibernateException e) {
      System.out.println("Failed: " + i);
    }

    session1.flush();
    session1.clear();
    session1.close();
  }
}
void save(){
对于(int i=0;i<5;i++){
会话session1=HibernateUtil.getSessionFactory().openSession();
事务处理=会话1.beginTransaction();
BatchSizeConf r=new BatchSizeConf();//这是我的实体
r、 setId(i);
r、 setDispatchType(“Disp”);
r、 尺寸(500);
试一试{
会话1.保存(r);
commit();
}捕获(休眠异常e){
System.out.println(“失败:+i”);
}
session1.flush();
会话1.clear();
session1.close();
}
}
我现在还有两个问题。

  • 可以像上面那样创建多个会话对象吗?(我有超过100000条记录。)
  • 我是否需要像上面那样调用
    flush()
    clear()
    close()
    方法

  • 这是不可能的,任何异常都会将事务标记为回滚

    为什么不将行切成块,并为每个块设置一个事务

    看看这个文档

    如果会话引发异常(包括任何SQLException),请立即回滚数据库事务,调用Session.close()并放弃会话实例。某些会话方法不会使会话保持一致状态。Hibernate引发的任何异常都不能视为可恢复的。通过在finally块中调用close()确保会话将被关闭


    你可以这样做

    Transaction tx = session.beginTransaction();
    ...
    for (BatchSizeConf  b: BatchSizeConfList) {
        ...
        tx.commit();
    }
    

    请参阅是。。我们可以做。。请参阅此代码

    public List<RecordErrorStatus> persistBatch(ArrayList<?> domainRecords) {
    
            List<RecordErrorStatus> fedRecordErrorStatusList = new ArrayList<RecordErrorStatus>();
            Session session = getSession();
            Transaction tx = session.beginTransaction();
            long rowCount = 0;
            boolean insertionFailed=false;
            for (Object object : domainRecords) {
                rowCount++;
                try {
                    System.out.println("Inserting Record:"+rowCount+object);
                    session.persist(object); // Persist the given transient instance
                    if (! this.rollBackOnFail) {
                        tx.commit();
                        tx = session.beginTransaction();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    RecordErrorStatus feedRecordStatus = new RecordErrorStatus();
                    feedRecordStatus.setRowNumber(String.valueOf(rowCount));
                    StringWriter sw = new StringWriter();
                    e.printStackTrace(new PrintWriter(sw));
                    String exceptionAsString = sw.toString();
                    feedRecordStatus.setErrorDescription(exceptionAsString);
                    fedRecordErrorStatusList.add(feedRecordStatus);
                    insertionFailed =true;
                    tx.rollback(); //Rollback the current record..
                    session.clear();//Clear the seesion.. If not, throws Nested Transaction not allowd...
                    tx = session.beginTransaction();//Start again..
                } 
            }
            if (this.rollBackOnFail && insertionFailed && ! tx.wasRolledBack()) {
                tx.rollback();
                System.out.println("Rollback");
            } 
            return fedRecordErrorStatusList;
        }
    
    公共列表持久化批处理(ArrayList domainRecords){
    List fedRecordErrorStatusList=新建ArrayList();
    Session=getSession();
    事务tx=会话.beginTransaction();
    长行计数=0;
    布尔插入失败=false;
    for(对象:domainRecords){
    行计数++;
    试一试{
    System.out.println(“插入记录:“+rowCount+object”);
    session.persist(object);//持久化给定的临时实例
    如果(!this.rollBackOnFail){
    tx.commit();
    tx=session.beginTransaction();
    }
    }捕获(例外e){
    e、 printStackTrace();
    RecordErrorStatus feedRecordStatus=新的RecordErrorStatus();
    feedRecordStatus.setRowNumber(String.valueOf(rowCount));
    StringWriter sw=新的StringWriter();
    e、 printStackTrace(新PrintWriter(sw));
    字符串异常AsString=sw.toString();
    feedRecordStatus.setErrorDescription(字符串除外);
    fedRecordErrorStatusList.add(feedRecordStatus);
    insertionFailed=true;
    tx.rollback();//回滚当前记录。。
    session.clear();//清除session..如果没有,则抛出嵌套事务not allowd。。。
    tx=session.beginTransaction();//重新启动。。
    } 
    }
    if(this.rollBackOnFail&&insertionFailed&&!tx.wasrollledback()){
    tx.回滚();
    System.out.println(“回滚”);
    } 
    返回fedRecordErrorStatusList;
    }
    

    谢谢@dgregory。我修改了我的代码,请看我修改过的问题。谢谢@Suresh Atta。我修改了我的代码,请看我修改过的问题。事务提交时不需要调用会话刷新。感谢您的帮助。