【问题标题】:Java Bulk Insert with Shared Entity Manager使用共享实体管理器的 Java 批量插入
【发布时间】:2017-06-07 18:37:33
【问题描述】:

我正在尝试编写一种将实体批量添加到数据库的方法。这是我的方法:

@Transactional
protected void bulkInsert(List<?> entities) {
    int batchSize = 25;
    AtomicInteger i = new AtomicInteger(0);
    try {
        em.getTransaction().begin();
        entities.parallelStream().forEach(e -> {
            em.persist(e);
            if ( i.get() > 0 && i.get() % batchSize == 0 ) {
                em.flush();
                em.clear();
            }
            i.incrementAndGet();
        });
        em.getTransaction().commit();
    } catch (RuntimeException e) {
        LOG.error("Error", e);
    } finally {
        if (em != null) {
            em.close();
        }
    }
}

但是当我运行它时,我收到以下错误:

java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:248) ~[spring-orm-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at com.sun.proxy.$Proxy145.getTransaction(Unknown Source) ~[na:na]

我尝试删除 @Transactional 注释,但仍然是同样的错误。我尝试通过 Session session = em.unwrap(Session.class); 使用 Session 但这仍然导致错误(虽然不同的错误)

如何批量插入对象?

【问题讨论】:

  • 您是否尝试删除em.getTransaction().begin();/em.getTransaction().commit(); 并离开@Transactional
  • @RomanPuchkovskiy 好的,我试过了,但它给了我一个错误:org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:526)
  • 包括@Transactional,请检查您添加的包。应该是org.springframework..... 。有时在不知不觉中添加javax.persistence.transactional... 时会发生这种情况。

标签: java database hibernate session bulkinsert


【解决方案1】:

在纯休眠中存在托管和非托管环境

非托管环境

如果 JPA 持久层在非托管环境中运行,则数据库连接通常由 Hibernate 的后台池机制处理。常见的实体管理器和事务处理习惯用法如下所示:

// 非托管环境成语

EntityManager em = emf.createEntityManager();实体交易 tx = 无效的;尝试 { tx = em.getTransaction(); tx.begin();

 // do some work
 ...

 tx.commit(); } catch (RuntimeException e) {
 if ( tx != null && tx.isActive() ) tx.rollback();
 throw e; // or display error message } finally {
 em.close(); }

使用 JTA 如果您使用 bean 管理事务 (BMT),代码将 看起来像这样:

// BMT 习语 @Resource public UserTransaction utx; @资源公开 EntityManagerFactory 工厂;

公共无效doBusiness(){ EntityManager em = factory.createEntityManager(); 试试 {

// do some work
...

utx.commit(); } catch (RuntimeException e) {
if (utx != null) utx.rollback();
throw e; // or display error message 
} finally {
em.close(); 

}

使用 EJB3 容器中的容器管理事务 (CMT),事务>划分是在会话 bean 注释中完成的 或部署描述符,而不是以编程方式。 EntityManager 将 在事务完成时自动刷新(如果你有 注入或查找EntityManager,它也会被关闭 自动地)。如果在EntityManager使用过程中出现异常, 如果您没有捕获到,事务回滚会自动发生 例外。由于 EntityManager 异常是 RuntimeExceptions 他们 将按照 EJB 规范回滚事务(系统 异常与应用程序异常)。

你应该跟随两个王子。

annotation @Transactional 它是spring annotaniot not hibernate。如果你没有配置它(或者你确实配置了 spring)就不起作用。

电脑

EntityManager 是一个廉价的、非线程安全的对象,它应该 一次,用于单个业务流程

调用 em.flush() ,em.clear() 可能很危险。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-09
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 1970-01-01
    相关资源
    最近更新 更多