我正在开发一个程序,该程序从文件读取并使用带有容器管理事务的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多秒。处理大文件时所花费的时间不合理。
是否有任何解决方法可以快速检查并插入记录,同时收到任何失败行的通知?
答案 0 :(得分: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 :-)
}
}
答案 1 :(得分: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
,因为容器已经决定回滚此事务。