使用JTA批量插入(EntityManager不能使用getTransaction)

时间:2013-11-13 21:42:13

标签: spring apache-camel spring-data batch-processing entitymanager

我正在使用spring数据和apache camel的项目,我们有2个数据库,Sql Server和带JTA的Oracle。问题出现是因为我需要从一个大文件中插入数据(大约10000000条记录),所以我决定使用批量插入作为:

@PersistenceContext(unitName="persistenceUnitSql")
EntityManager em;

public void insertBatch() {
    em.getTransaction().begin();
    for (int i = 1; i <= 1000000; i++) {
      Point point = new Point(i, i);
      em.persist(point);
      if ((i % 10000) == 0) {
          em.getTransaction().commit();
          em.clear();          
          em.getTransaction().begin();
      }
    }
    em.getTransaction().commit();
}

但是发生了这个问题:

    A JTA EntityManager cannot use getTransaction()

任何帮助......

2 个答案:

答案 0 :(得分:1)

自我控制JTA交易似乎比预期的要困难得多。我通常使用的一种解决方法是使用单独的服务&#34;哪一个插入,你在该方法上设置REQUIRES_NEW事务传播策略,所以它看起来像:

class FooService {

    private PointPersister pointPersister;

    @Transactional(propagation=REQUIRED)
    public void insertBatch() {
        List<Point> points = new ArrayList<Point>(10000);
        for (int i = 1; i <= 1000000; i++) {
            points.add(new Point(i,1));
            if ((i % 10000) == 0) {
                pointPersister.insertPointBatch(points);
            }
        }
    }
}

class PointPersisterImpl implements PointPersister {
    @PersistenceContext
    private EntityManager em;

    @Transactional(propagation=REQUIRES_NEW)    // in a separate txn
    public void insertPointBatch(List<Point> points) {
        // persist points
    }
}

您还可以做出其他选择,以避免处理麻烦且容易出错的手动事务处理。 Spring Batch是可能的解决方案之一。

答案 1 :(得分:0)

我通过以下方式解决了这个问题:

@PersistenceUnit(unitName="persistenceUnitSql") 
// from persistence xml <persistence-unit name="persistenceUnitSql" transaction-type="JTA"> 
private EntityManagerFactory emf;

@Autowired
private JtaTransactionManager transactionManagerSqlServer;
// from application-context.xml
//<bean class="org.springframework.transaction.jta.JtaTransactionManager" id="transactionManagerSqlServer" />

public List<Point> insertBatch(List<Point> datos) {

    try {
        UserTransaction transaction = transactionManagerSqlServer.getUserTransaction();     
        transaction.begin();
        EntityManager em = emf.createEntityManager();

        for (Point punto : datos) {
            em.persist(punto);
        }
        transaction.commit();
        em.close();
    } catch (NotSupportedException e) {
        LOGGER.error(e);
    } catch (SystemException e) {
        LOGGER.error(e);
    } catch (SecurityException e) {
        LOGGER.error(e);
    } catch (IllegalStateException e) {
        LOGGER.error(e);
    } catch (RollbackException e) {
        LOGGER.error(e);
    } catch (HeuristicMixedException e) {
        LOGGER.error(e);
    } catch (HeuristicRollbackException e) {
        LOGGER.error(e);
    }       

    return datos;
}