gpt4 book ai didi

java - Hibernate 更快的 EntityManagerFactory 创建

转载 作者:IT老高 更新时间:2023-10-28 20:29:48 25 4
gpt4 key购买 nike

在我的桌面应用程序中,新数据库经常被打开。我使用 Hibernate/JPA 作为 ORM。问题是,创建 EntityManagerFactory 非常慢,在快速机器上大约需要 5-6 秒。我知道 EntityManagerFactory 应该是重量级的,但这对于用户希望快速打开新数据库的桌面应用程序来说太慢了。

  1. 我可以关闭一些 EntityManagerFactory 功能来获取实例吗快点?或者是否可以懒惰地创建一些 EntityManagerFactory 来加快创建速度?

  2. 我可以在之前以某种方式创建 EntityManagerFactory 对象吗知道数据库网址?我很乐意关闭所有验证这是可能的。

  3. 通过这样做,我可以合并 EntityManagerFactory 以供以后使用吗?

  4. 还有其他想法如何更快地创建 EntityManagerFactory 吗?

更新更多信息和 JProfiler 分析

桌面应用程序可以打开保存的文件。我们的应用程序文档文件格式由 1 个 SQLite 数据库 + 和 ZIP 文件中的一些二进制数据组成。打开文档时,会提取 ZIP 并使用 Hibernate 打开数据库。数据库都具有相同的架构,但显然不同的数据。

我第一次打开文件的时间似乎比接下来的时间长得多。我使用 JProfiler 分析了第一次和第二次运行并比较了结果。

第一次运行:

create EMF: 4385ms
build EMF: 3090ms
EJB3Configuration configure: 900ms
EJB3Configuration <clinit>: 380ms

calltree1.png .

第二次运行:

create EMF: 1275ms
build EMF: 970ms
EJB3Configuration configure: 305ms
EJB3Configuration <clinit>: not visible, probably 0ms

compare_calltree.png .

在调用树比较中,您可以看到一些方法明显更快(以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

热点比较现在有了有趣的结果:

screenshot compare_hotspot.png .

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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com