在我的桌面应用程序中,新数据库经常被打开。我使用 Hibernate
/JPA
作为 ORM。
问题是,创建 EntityManagerFactory
非常慢,在快速机器上大约需要 5-6 秒。我知道 EntityManagerFactory
应该是重量级的,但这对于用户希望快速打开新数据库的桌面应用程序来说太慢了。
我可以关闭一些 EntityManagerFactory 功能来获取实例吗 快点?或者是否可以懒惰地创建一些 EntityManagerFactory 来加快创建速度?
我可以在之前以某种方式创建 EntityManagerFactory 对象吗 知道数据库网址?我很乐意关闭所有 验证这是可能的。
通过这样做,我可以合并 EntityManagerFactory 以供以后使用吗?
还有其他想法如何更快地创建 EntityManagerFactory 吗?
更新更多信息和 JProfiler 分析
桌面应用程序可以打开保存的文件。我们的应用程序文档文件格式由 1 个 SQLite 数据库 + 和 ZIP 文件中的一些二进制数据组成。打开文档时,会提取 ZIP 并使用 Hibernate 打开数据库。数据库都具有相同的架构,但显然不同的数据。
我第一次打开文件的时间似乎比接下来的时间长得多。 我使用 JProfiler 分析了第一次和第二次运行并比较了结果。
第一次运行:
create EMF: 4385ms
build EMF: 3090ms
EJB3Configuration configure: 900ms
EJB3Configuration <clinit>: 380ms
.
第二次运行:
create EMF: 1275ms
build EMF: 970ms
EJB3Configuration configure: 305ms
EJB3Configuration <clinit>: not visible, probably 0ms
.
在调用树比较中,您可以看到一些方法明显更快(以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
热点比较现在有了有趣的结果:
.
ClassLoader.loadClass: -1686ms
XMLSchemaFactory.newSchema: -184ms
ClassFile.<init>: -109ms
我不确定是加载 Hibernate 类还是我的 Entity 类。
第一个改进是在应用程序启动后立即创建一个 EMF,以初始化所有必要的类(我有一个空的 db 文件作为我的应用程序附带的原型(prototype))。 @sharakan 谢谢你的回答,也许 DeferredConnectionProvider 已经可以解决这个问题了。
接下来我将尝试 DeferredConnectionProvider!但我们也许可以进一步加快速度。您还有什么建议吗?
最佳答案
您应该能够通过将自己的 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();
}
}
如何使用它的粗略示例:
// 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);
您可以将 EntityManagerFactory
的初始设置放在单独的线程或其他东西上,这样用户就不必等待它。那么在指定连接信息之后,他们唯一需要等待的就是连接池的设置,这与解析对象模型相比应该是相当快的。
关于java - Hibernate 更快的 EntityManagerFactory 创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15036233/