【问题标题】:EclipseLink batch writing not working in a JPA/JTA applicationEclipseLink 批量写入在 JPA/JTA 应用程序中不起作用
【发布时间】:2013-04-11 21:32:55
【问题描述】:

我正在 Glassfish 3.1.2.2、EclipseLink 2.3.2 上编写 JPA 应用程序。我也在使用 Spring MVC,使用容器管理的 EntityManager(@PersistenceContext 由 Spring 注入,但由容器通过 jee:jndi-lookup 创建)

我在persistence.xml 中将eclipselink.jdbc.batch-writing 设置为JDBC,但它没有按预期工作。

我的代码有一个相当简单的循环来编写一堆对象

 UserTransaction tx = ...;
 tx.begin();
 for (MyObject obj : list) { 
   entityManager.persist(obj);
 }
 tx.commit();

如果我将 UserTransaction 替换为方法周围的 @Transactional 注释,确实可以批量写入!

我看到为每个持久调用创建了一个单独的工作单元:

FINER: client acquired: 3418589
FINER: TX binding to tx mgr, status=STATUS_ACTIVE
FINER: acquire unit of work: 11053522
FINEST: persist() operation called on: mypkg.MyClass@1252ed8
....
FINER: client acquired: 23361578
FINER: TX binding to tx mgr, status=STATUS_ACTIVE
FINER: acquire unit of work: 17636998
FINEST: persist() operation called on: mypkg.MyClass@1252ed8

正如预期的那样,在提交之前,数据库操作实际上不会执行 - 但每个工作单元都有自己的批次:

FINER: TX beforeCompletion callback, status=STATUS_ACTIVE
FINER: begin unit of work commit
FINER: TX beginTransaction, status=STATUS_ACTIVE
FINEST: Execute query InsertObjectQuery(mypkg.MyClass@12a46ef)
FINEST: Connection acquired from connection pool [default].
FINEST: Execute query  
FINER: Begin batch statements
FINE: INSERT INTO ....
FINE:   bind => [24 parameters bound]
FINER: End Batch Statements

任何想法我错过了什么?我认为问题的根源在于每个持久化的单独工作单元。

注意确实看到了在单个工作单元中通过单个持久性级联的子实体的批处理工作。但是每组父/子都是一个单独的批次。

【问题讨论】:

  • 您使用的 JDBC 驱动程序是否支持批量写入。
  • 甲骨文。当我直接使用 JDBC(不是通过 JPA)时,JDBC 驱动程序支持批处理
  • 另见编辑评论
  • 这是一个 spring 配置问题,因为似乎每个持久化都发生在 spring EM 包装器下的不同 EntityManager 上下文中。 Spring 为每个持久调用启动一个新的 EM,强制每个插入位于单独的语句中,而批处理要求它们都位于单个 EM 上下文中。请显示如何获得 EM 的弹簧设置。您还可以尝试从包装器中获取委托 EclipseLink EM 并将其作为解决方法重用。
  • @Chris - 你是对的,虽然我注意到在 Java EE/JSF 应用程序中使用 UserTransaction 时的行为相同。那是Spring的错误吗?还是 Java EE 错误? (@Transactional 注释没有这个问题。)感谢您提供关于展开的提示。把它作为一个答案,我会接受的。

标签: spring jpa eclipselink


【解决方案1】:
  • 对于Oracle,可以尝试在persistence.xml中配置。

    <property name="eclipselink.jdbc.batch-writing" value="Oracle-JDBC"/>

    来自文档:

    oracle-jdbc:使用Oracle平台原生的批量写入。在属性映射中,使用 OracleJDBC。

    注意:这需要 Oracle JDBC 驱动程序。

  • 另外,也可以通过属性来配置。

    propertyMap.put(PersistenceUnitProperties.BATCH_WRITING, BatchWriting.OracleJDBC);

结合批量写入,可以有eclipselink.jdbc.batch-writing.size指定批量大小。

[帖子是 EclipseLink 特有的,我对 Spring 不太熟悉]

【讨论】:

    【解决方案2】:

    您似乎在混合 Java EE 事务和 Spring 事务。您需要使用其中一个。

    如果你想使用JTA,你需要配置你的persistence.xml来使用JTA,并确保你正确设置了“eclipselink.target-server”(如果你从Glassfish访问它会默认设置) ,但如果你从 Spring 访问它就不会)。

    【讨论】:

    • persistence.xml 已设置为使用 JTA。 eclipselink.target-server 已经设置好了。并且 Spring 被配置为使用 <tx:jta-transaction-manager>,因此 Spring @Transactional 注释仍在使用底层 JTA 事务。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    • 1970-01-01
    • 2021-03-09
    • 2016-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多