【发布时间】: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