在针对我的本地数据库开发应用程序时,事务速度没有问题,尽管每秒执行多个事务时 CPU 使用率始终保持在 30% 左右,并且在进行分析时,大部分时间都花在处理事务的 javax 方法中每笔交易平均需要 2.6 秒。因此,我使用 ArrayList 作为缓冲区,仅在缓冲区大小超过 300 个实例时才发送事务,这显着降低了 CPU 使用率。
当我将 persistence.xml 更改为使用远程数据库时(同时检查了 RDS 和个人的异地数据库),持久化/提交一批实例的最短时间约为 20 秒,这太高了,因为每 5 秒(平均)需要一次 300 个实例的事务。
我试图将 EntityManager 的刷新模式更改为,FlushModeType.COMMIT
但它并没有明显改变性能。由于某些(对我而言)未知的原因,在发送之前增加缓冲区的大小会导致 javax.persistence 库的堆栈溢出。
持久性.xml
<persistence-unit name="PU-data" transaction-type="RESOURCE_LOCAL">
<mapping-file>META-INF/orm.xml</mapping-file>
... // class, shared-cache-mode=none, validation-mode=none ...
<properties>
... // Authentication ...
<!-- Optimization attempts -->
<property name="eclipselink.jdbc.bind-parameters" value="true" />
<property name="eclipselink.jdbc.batch-writing" value="JDBC"/>
<property name="eclipselink.jdbc.batch-writing.size" value="300" />
<property name="eclipselink.jdbc.cache-statements" value="true" />
<property name="eclipselink.cache.shared.default" value="false" />
<property name="eclipselink.persistence-context.close-on-commit" value="true" />
<property name="eclipselink.persistence-context.flush-mode" value="commit" />
<property name="eclipselink.persistence-context.persist-on-commit" value="false" />
</properties>
</persistence-unit>
处理事务的门面
MouseFacade.bufferSemaphore.acquireUninterruptibly(1);
if (MouseFacade.buffer.size() >= 300) {
EntityManager entityManager = EMF.getEntityManager();
try {
entityManager.getTransaction().begin();
for (Mouse mouse : MouseFacade.buffer) {
entityManager.persist(mouse);
}
entityManager.getTransaction().commit();
} finally {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
entityManager.close();
MouseFacade.buffer.clear();
}
}
MouseFacade.bufferSemaphore.release(1);
ORM 映射
<entity-mappings version="2.1" xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<entity class="se.my.package.Mouse">
<table-generator name="ORD_SEQ" allocation-size="300"/>
</entity>
</entity-mappings>
更新
我已经浏览了此页面上的建议,称为如何将 JPA 性能提高 1,825% ( http://java-persistence-performance.blogspot.se/2011/06/how-to-improve-jpa-performance- by-1825.html),但是没有什么区别,这让我想知道我是否错过了关于批处理写入和 MySQL 的关键点。我重写了实体以不依赖关系,并将整个应用程序的读取操作最小化为 1,以便只关注写入问题。
查看 EclipseLink 日志时,看起来根本没有使用批量写入,而是为每个似乎正确的实例写入了 2 个日志整体(300 个实例 * 2 个连接 * 24 延迟 = 14.4 秒)。
[EL Fine]: sql: 2013-03-31 01:35:29.249--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--SELECT LAST_INSERT_ID()
[EL Fine]: sql: 2013-03-31 01:35:29.274--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--INSERT INTO mouse (event, posX, posY, created, uid) VALUES (?, ?, ?, ?, ?)
bind => [12, 241, 250, 1364690113727, 1]
[EL Fine]: sql: 2013-03-31 01:35:29.298--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--SELECT LAST_INSERT_ID()
[EL Fine]: sql: 2013-03-31 01:35:29.323--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--INSERT INTO mouse (event, posX, posY, created, uid) VALUES (?, ?, ?, ?, ?)
bind => [12, 233, 296, 1364690113443, 1]
...
进步
By changing to @GeneratedValue(strategy = GenerationType.TABLE)
and allocationSize=300
I've managed to reduce the number of requests by 50%, although it looks as if bind are still sent on their own when checking the EclipseLink log, even though batch writing is supposedly enabled.
[EL Fine]: sql: 2013-03-31 01:35:29.323--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--INSERT INTO mouse (event, posX, posY, created, uid) VALUES (?, ?, ?, ?, ?)
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]
bind => [..., ..., ..., ..., ...]