【发布时间】:2017-10-22 02:42:06
【问题描述】:
我有大量使用 EMF/Texo 组合生成和注释的类。我使用 JPA/Eclipselink 将它们保存在 SQL Server 数据库中。
这很好用,但是当需要持久化大量对象时性能很差。所以我写了两个测试用例(参见TestBulkInserts.java),它们比较了使用框架(foo)的大容量插入和普通的JDBC大容量插入(bar)的性能。
当插入 10000 个对象时,这是低于平均大小的批量插入。 foo() 和 bar() 给出以下时间:
JPA/Texo 持续时间:19.620 毫秒
纯 JDBC 持续时间:892 毫秒
我想知道为什么会有如此巨大的差异(超过 20 倍!)。更大的尺寸甚至会变得更糟。
DatabaseObject 类扩展了 PersistableObjectClass.java(见下文),两者都是使用 Texo + EMF 生成的(包括各自的 DAO 类)。
我没有在persistence.xml 中添加任何特定设置,除了必要的连接细节。
TestBulkInserts.java:
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
...
import com.ownproject.loader.generated.DbModelPackage;
import com.ownproject.loader.DatabaseObject;
import com.ownproject.loader.dao.DatabaseObjectDao;
import javax.persistence.Persistence;
import org.eclipse.emf.texo.server.store.EntityManagerProvider;
import org.junit.Test;
public class TestBulkInserts {
private static final int NUM_LOOPS = 10000;
@Test
public void foo() {
TestMethods.connectTestDBandEMF();
// basically does this
// DbModelPackage.initialize();
// EntityManagerProvider.getInstance().setEntityManagerFactory(Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_TEST));
Stopwatch sw = Stopwatch.createStarted();
DatabaseObjectDao dao = new DatabaseObjectDao();
dao.getEntityManager().getTransaction().begin();
for (int i = 0; i < NUM_LOOPS; i++) {
DatabaseObject dbo = new DatabaseObject();
dbo.setString(UUID.randomUUID().toString());
dbo.setInsert_time(Date.valueOf(LocalDate.now()));
dao.insert(dbo);
}
dao.getEntityManager().getTransaction().commit();
sw.stop();
System.out.println(String.format("Duration JPA/Texo: %,dms", sw.elapsed(TimeUnit.MILLISECONDS)));
}
@Test
public void bar() throws ClassNotFoundException, SQLException {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String connectionUrl = "jdbc:sqlserver://hostname:1433;databaseName=local_test;user=sa;password=blablub;";
Connection con = DriverManager.getConnection(connectionUrl);
con.setAutoCommit(false);
Stopwatch sw = Stopwatch.createStarted();
PreparedStatement insertStatement = con.prepareStatement("INSERT INTO DatabaseObject(b_id, insert_time) VALUES (?, ?)");
for (int i = 0; i < NUM_LOOPS; i++) {
insertStatement.setString(1, UUID.randomUUID().toString());
insertStatement.setDate(2, Date.valueOf(LocalDate.now()));
insertStatement.addBatch();
}
insertStatement.executeBatch();
con.commit();
con.close();
sw.stop();
System.out.println(String.format("Duration plain JDBC: %,dms", sw.elapsed(TimeUnit.MILLISECONDS)));
}
}
PersistableObjectClass.java:
import javax.persistence.Basic;
...
import javax.persistence.TemporalType;
@Entity(name = "PersistableObjectClass")
@MappedSuperclass()
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class PersistableObjectClass {
@Basic()
@Temporal(TemporalType.TIMESTAMP)
private Date insert_time = null;
@Id()
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int s_id = 0;
...
}
【问题讨论】:
-
感谢您的提示!你是说内存问题吗?因为刷新并没有减少加载时间。
-
JPA 增加了开销,因此可以预料会有一些差异,但是有太多变量无法解释您的数字。您是否打开了登录以查看生成的 SQL,以确保您确实在进行苹果对苹果的比较?您在 JPA/EclipseLink 中使用了哪些设置?为什么您使用 Identity 进行序列管理,而不是允许与您的批量大小匹配的预分配?
标签: java jpa jdbc eclipselink emf