use*_*011 24 java sql orm hibernate jpa
在我的桌面应用程序中,新数据库经常打开.我使用Hibernate/ JPA作为ORM.问题是,创建EntityManagerFactory速度相当慢,在快速机器上花费大约5-6秒.我知道它EntityManagerFactory应该是重量级的,但对于用户希望快速打开新数据库的桌面应用程序来说这太慢了.
我可以关闭一些EntityManagerFactory功能来更快地获取实例吗?或者是否可以懒惰地创建一些EntityManagerFactory来加速cration?
在知道数据库url之前,我可以以某种方式创建EntityManagerFactory对象吗?我很乐意关闭所有可能的验证.
通过这样做,我可以集合EntityManagerFactorys供以后使用吗?
任何其他想法如何更快地创建EntityManagerFactory?
更新更多信息和JProfiler分析
桌面应用程序可以打开保存的文件.我们的应用程序文档文件格式包含1个SQLite数据库+以及ZIP文件中的一些二进制数据.打开文档时,将解压缩ZIP并使用Hibernate打开数据库.数据库都具有相同的模式,但显然有不同的数据.
看来我第一次打开文件时需要比以下时间长得多.我用JProfiler描述了第一次和第二次运行并比较了结果.
第一轮:
create EMF: 4385ms
build EMF: 3090ms
EJB3Configuration configure: 900ms
EJB3Configuration <clinit>: 380ms
Run Code Online (Sandbox Code Playgroud)
.
第二轮:
create EMF: 1275ms
build EMF: 970ms
EJB3Configuration configure: 305ms
EJB3Configuration <clinit>: not visible, probably 0ms
Run Code Online (Sandbox Code Playgroud)
.
在调用树比较中,您可以看到某些方法明显更快(DatabaseManager.作为起点):
create EMF: -3120ms
Hibernate create EMF: -3110ms
EJB3Configuration configure: -595ms
EJB3Configuration <clinit>: -380ms
build EMF: -2120ms
buildSessionFactory: -1945ms
secondPassCompile: -425ms
buildSettings: -346ms
SessionFactoryImpl.<init>: -1040ms
Run Code Online (Sandbox Code Playgroud)
热点比较现在有了有趣的结果:
.
ClassLoader.loadClass: -1686ms
XMLSchemaFactory.newSchema: -184ms
ClassFile.<init>: -109ms
Run Code Online (Sandbox Code Playgroud)
我不确定是加载Hibernate类还是我的Entity类.
第一个改进是在应用程序启动后立即创建一个EMF,以初始化所有必需的类(我有一个空的db文件作为我的应用程序附带的原型).@sharakan感谢您的回答,也许DeferredConnectionProvider已经是这个问题的解决方案.
我接下来会尝试DeferredConnectionProvider!但我们可能会进一步加快速度.你有什么建议吗?
sha*_*kan 11
你应该能够通过实现你自己ConnectionProvider作为一个真实的装饰器来做到这一点ConnectionProvider.
这里的关键观察是,在创建ConnectionProvider之前不会使用EntityManager它(请参阅注释以supportsAggressiveRelease()获取警告).因此,您可以创建一个DeferredConnectionProvider类,并使用它来构造EntityManagerFactory,然后等待用户输入,并在实际创建任何EntityManager实例之前执行延迟初始化.我把它写成一个包装器ConnectionPoolImpl,但你应该能够使用任何其他实现ConnectionProvider作为基础.
public class DeferredConnectionProvider implements ConnectionProvider {
private Properties configuredProps;
private ConnectionProviderImpl realConnectionProvider;
@Override
public void configure(Properties props) throws HibernateException {
configuredProps = props;
}
public void finalConfiguration(String jdbcUrl, String userName, String password) {
configuredProps.setProperty(Environment.URL, jdbcUrl);
configuredProps.setProperty(Environment.USER, userName);
configuredProps.setProperty(Environment.PASS, password);
realConnectionProvider = new ConnectionProviderImpl();
realConnectionProvider.configure(configuredProps);
}
private void assertConfigured() {
if (realConnectionProvider == null) {
throw new IllegalStateException("Not configured yet!");
}
}
@Override
public Connection getConnection() throws SQLException {
assertConfigured();
return realConnectionProvider.getConnection();
}
@Override
public void closeConnection(Connection conn) throws SQLException {
assertConfigured();
realConnectionProvider.closeConnection(conn);
}
@Override
public void close() throws HibernateException {
assertConfigured();
realConnectionProvider.close();
}
@Override
public boolean supportsAggressiveRelease() {
// This gets called during EntityManagerFactory construction, but it's
// just a flag so you should be able to either do this, or return
// true/false depending on the actual provider.
return new ConnectionProviderImpl().supportsAggressiveRelease();
}
}
Run Code Online (Sandbox Code Playgroud)
一个如何使用它的粗略示例:
// Get an EntityManagerFactory with the following property set:
// properties.put(Environment.CONNECTION_PROVIDER, DeferredConnectionProvider.class.getName());
HibernateEntityManagerFactory factory = (HibernateEntityManagerFactory) entityManagerFactory;
// ...do user input of connection info...
SessionFactoryImpl sessionFactory = (SessionFactoryImpl) factory.getSessionFactory();
DeferredConnectionProvider connectionProvider = (DeferredConnectionProvider) sessionFactory.getSettings()
.getConnectionProvider();
connectionProvider.finalConfiguration(jdbcUrl, userName, password);
Run Code Online (Sandbox Code Playgroud)
您可以将初始设置EntityManagerFactory放在单独的线程或其他东西上,这样用户就不必等待它.然后,在指定连接信息之后,他们唯一要等待的是设置连接池,与解析对象模型相比,这应该相当快.
| 归档时间: |
|
| 查看次数: |
5498 次 |
| 最近记录: |