1

我正在开发一个程序,该程序使用带有容器管理事务的 JTA/EclipseLink 2.3.x JPA 从文件中读取并逐行插入 Oracle 11g 数据库。

我已经开发了下面的代码,但我对失败的行需要知道并手动修复这一事实感到困惑。

public class CreateAccount {
    @PersistenceContext(unitName="filereader")
    private EntityManager em;
    private ArrayList<String> unprocessed;

    public void upload(){
        //reading the file into unprocessed
        for (String s : unprocessed) {
            this.process(s);
        }
    }

    private void process(String s){
        //Setting the entity with appropriate properties.
        //Validate the entity
        em.persist(account);
    }
}

第一个版本需要几秒钟来将 5000 行提交到数据库,因为它似乎利用了缓存准备好的语句。当所有要持久化的实体都有效时,这可以正常工作。但是,我担心即使我验证了实体,仍然有可能由于各种意外原因而失败,并且当任何实体在提交期间抛出异常时,我找不到导致它的特定记录,并且所有实体都已经回滚。

我尝试了另一种方法,即在进程(String s)中使用以下代码启动一个新事务并为每一行提交而不使用托管事务。

    for (String s : unprocessedLines) {
        try {
            em.getTransaction().begin();
            this.process(s);
            em.getTransaction().commit();
        } catch (Exception e) {
            // Any exception that a line caused can be caught here
            e.printStackTrace();
        }
    }

第二个版本非常适合记录错误行,因为捕获并处理了由单个行引起的异常,但是将相同的 5000 行提交到数据库需要 300 多秒。处理大文件时所花费的时间是不合理的。

是否有任何解决方法可以让我快速检查和插入记录,同时收到任何失败行的通知?

4

2 回答 2

0

那么这更有可能是一个猜测,但是你为什么不尝试保持事务并批量提交它,那么你将保持回滚异常同时保持速度:

try {
 em.getTransaction().begin();
 for (String s : unprocessedLines) {
            this.process(s);
    }
 em.getTransaction().commit();
} catch (RollbackException exc) { 
 // here you have your rollback reason 
} finally {
  if(em.getTransaction.isActive()) {
      em.getTransaction.rollback(); // well of course you should declare em.getTransaction as a varaible above instead of constantly invoking it as I do :-)
   }
}
于 2013-08-10T20:19:06.660 回答
0

我的解决方案原来是二分搜索,并从一个合理数字的块开始,例如 last = first + 1023 以最小化树的深度。

但是,请注意,这仅在错误是确定性的情况下才有效,并且如果错误率非常高,则比提交每条记录一次更糟糕。

private boolean batchProcess(int first, int last){
    try {
        em.getTransaction().begin();
        for (String s : unprocessedLines.size(); i++) {
            this.process(s);
        }
        em.getTransaction().commit();
    } catch (Exception e) {
        e.printStackTrace();
        if(em.getTransaction.isActive()) {
            em.getTransaction.rollback();
        }
        if( first == last ){
            failedLine.add(unprocessedLines(first));
        } else {
            int mid = (first + last)/2+1
            batchProcess(first, mid-1);
            batchProcess(mid, last);
        }
    }
}

对于容器管理的事务,可能需要在事务的上下文之外进行二分查找,否则会RollbackException因为容器已经决定回滚这个事务。

于 2015-08-29T11:14:39.537 回答