在我的桌面应用程序中,新的数据库经常被打开。我使用Hibernate
/JPA
作为ORM。问题是,创建EntityManagerFactory
非常慢,在快速的机器上大约需要5-6秒。我知道EntityManagerFactory
应该是重量级的,但这对于用户期望快速打开新数据库的桌面应用程序来说太慢了。
1.我可以关闭一些EntityManagerFactory特性来更快地获得示例吗?或者可以延迟创建一些EntityManagerFactory来加快创建速度吗?
1.我可以在知道数据库url之前创建EntityManagerFactory对象吗?我很乐意关闭所有验证。
1.通过这样做,我可以池化EntityManagerFactorys供以后使用吗?
1.如何更快地创建EntityManagerFactory?
更新更多信息和JProfiler分析
桌面应用程序可以打开保存的文件。我们的应用程序文档文件格式由1个SQLite数据库+和ZIP文件中的一些二进制数据组成。当打开文档时,ZIP被提取,并使用Hibernate打开数据库。数据库都具有相同的模式,但数据明显不同。
我第一次打开一个文件的时间似乎比后面的时间要长得多。我用JProfiler分析了第一次和第二次运行的情况,并比较了结果。
第1次运行:
create EMF: 4385ms
build EMF: 3090ms
EJB3Configuration configure: 900ms
EJB3Configuration <clinit>: 380ms
.
第2次运行:
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文件作为我的应用程序已经附带的原型)。
我将尝试DeferredConnectionProvider下一个!但我们可能能够加快它甚至进一步.你有任何更多的建议?
2条答案
按热度按时间omqzjyyz1#
您应该能够通过将自己的
ConnectionProvider
实现为真实的的ConnectionProvider
的装饰器来实现这一点。这里的关键观察结果是,在创建
EntityManager
之前不会使用ConnectionProvider
(请参阅supportsAggressiveRelease()
中的注解以获得警告)。因此,您可以创建一个DeferredConnectionProvider
类,并使用它来构造EntityManagerFactory
,但随后等待用户输入,并在实际创建任何EntityManager
示例之前进行延迟初始化。我将其作为ConnectionPoolImpl
的 Package 器编写,但是您应该能够使用ConnectionProvider
的任何其他实现作为基础。一个简单的例子来说明如何使用它:
你可以把
EntityManagerFactory
的初始设置放在一个单独的线程上,这样用户就不必等待它了。然后,在指定连接信息之后,他们唯一要等待的就是连接池的设置,与解析对象模型相比,这应该是相当快的。twh00eeo2#
EMF并没有太多的特性,除了初始化JDBC连接/池。
我建议您不要在用户注意到性能下降时才懒洋洋地创建EMF,而应该朝着相反的方向前进-在用户真正需要EMF之前主动创建EMF。在应用程序初始化期间(或者至少在您了解数据库时)在单独的线程中创建EMF一次。在整个应用程序/数据库存在期间重用它。
不-它创建一个JDBC连接。
我觉得更好的问题是:为什么你的应用程序会动态地发现数据库连接URL?你是说你的数据库是动态创建/提供的,没有办法提前预测连接参数。这真的是要避免的。
不,你不能共享电磁场。你可以共享的是连接。
我同意- 6秒对于EMF的初始化来说太慢了。
我怀疑这与你选择的数据库技术比JPA/JDBC/JVM更有关系。我的猜测是,也许你的数据库在你连接时正在初始化自己。你使用Access吗?你使用什么DB?
您是否通过WAN连接到远程数据库?网络速度/延迟是否良好?
客户端PC的性能是否受到限制?
编辑:评论后添加
将自己的ConnectionProvider实现为围绕真实的ConnectionProvider的装饰器根本不会加快用户体验。数据库示例仍然需要初始化,EMF & EM创建,JDBC连接仍然需要随后建立。
选项:
1.共享一个公共的预加载数据库示例:对于您的业务场景似乎是不可能的(尽管JSE技术支持这一点,并且还支持客户机-服务器设计)。
1.更改为启动速度更快的DB:Derby(又名Java DB)包含在现代JVM中,启动时间约为1.5秒(冷)和0.7秒(热-预加载数据)。
1.在许多在大多数情况下,最快的解决方案是使用JAXB和STAX将数据直接加载到内存中的java对象中(特别是使用像map、hashing和arraylists这样的智能结构)。就像JPA可以将POJO类Map到数据库表和列一样,因此JAXB可以将POJO类Map到XML模式,并使用XML文档示例。如果您有非常复杂查询,使用基于SQL集的逻辑,并使用多个连接和大量使用DB索引,那么这将是不可取的。
(2)可能会在有限的努力下得到最好的改善。
此外:- 尝试在部署期间而不是在应用程序使用期间解压缩数据文件。-在与UI启动并行运行的启动线程中初始化EMF-尝试启动DB初始化作为应用程序的第一步之一(这意味着使用JDBC连接到实际示例)。