Hibernate更快地创建EntityManagerFactory [英] Hibernate faster EntityManagerFactory creation

查看:131
本文介绍了Hibernate更快地创建EntityManagerFactory的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


  1. 我可以关闭一些EntityManagerFactory功能以使实例
    更快吗?或者是否可以创建一些EntityManagerFactory来加速缓存?


  2. 我可以以某种方式创建EntityManagerFactory对象,知道数据库url之前的
    ?我很乐意关闭所有的
    验证功能。

  3. 通过这样做,我可以将EntityManagerFactorys集中以备后用吗?

    / p>
  4. 其他想法如何更快创建EntityManagerFactory?

使用更多信息和JProfiler分析进行更新



桌面应用程序可以打开保存的文件。我们的应用程序文档文件格式由1个SQLite数据库+和ZIP文件中的一些二进制数据组成。当打开一个文档时,ZIP被解压缩并且数据库用Hibernate打开。这些数据库都有相同的模式,但显然不同的数据。



似乎我第一次打开一个文件需要比以下时间长得多的时间。
我用JProfiler描述了第一次和第二次运行并比较了结果。 p $ p $ 创建EMF:4385ms
构建EMF:3090ms
EJB3Configuration configure:900ms
EJB3Configuration< clinit>:380ms



第二次运行:

 创建EMF:1275ms 
build EMF:970ms
EJB3Configuration configure:305ms
EJB3Configuration< clinit> ;:不可见,可能是0ms



在Call tr​​ee比较中,您可以看到有些方法明显更快(DatabaseManager。作为起点):

 创建EMF:-3120ms 
Hibernate创建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类或我的实体类。

第一个改进是在应用程序启动时立即创建一个EMF,以便初始化所有必需的类(我有一个空的db文件作为原型SH撇开我的申请)。 @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;

$ b $ 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);

$ b $ private void assertConfigured(){
if(realConnectionProvider == null){
throw new IllegalStateException(Not configured yet!);
}
}

@Override
public Connection getConnection()throws SQLException {
assertConfigured();

返回realConnectionProvider.getConnection();
}

@Override
public void closeConnection(Connection conn)throws SQLException {
assertConfigured();

realConnectionProvider.closeConnection(conn);
}

@Override
public void close()throws HibernateException {
assertConfigured();

realConnectionProvider.close();

$ b @Override
public boolean supportsAggressiveRelease(){
//在EntityManagerFactory构造期间被调用,但它是
//只是一个标志你应该能够做到这一点,或者根据实际的提供者返回
// true / false。
返回新的ConnectionProviderImpl()。supportsAggressiveRelease();
}
}

如何使用它的一个粗略示例: p>

  //使用以下属性设置获取EntityManagerFactory:
// properties.put(Environment.CONNECTION_PROVIDER,DeferredConnectionProvider.class .getName());
HibernateEntityManagerFactory factory =(HibernateEntityManagerFactory)entityManagerFactory;

// ...做用户输入的连接信息...

SessionFactoryImpl sessionFactory =(SessionFactoryImpl)factory.getSessionFactory();
DeferredConnectionProvider connectionProvider =(DeferredConnectionProvider)sessionFactory.getSettings()
.getConnectionProvider();

connectionProvider.finalConfiguration(jdbcUrl,userName,password);

您可以将 EntityManagerFactory

In my desktop application new databases get opened quite often. I use Hibernate/JPA as an ORM. The problem is, creating the EntityManagerFactory is quite slow, taking about 5-6 Seconds on a fast machine. I know that the EntityManagerFactory is supposed to be heavyweight but this is just too slow for a desktop application where the user expects the new database to be opened quickly.

  1. Can I turn off some EntityManagerFactory features to get an instance faster? Or is it possible to create some of the EntityManagerFactory lazily to speed up cration?

  2. Can I somehow create the EntityManagerFactory object before knowing the database url? I would be happy to turn off all validation for this to be possible.

  3. By doing so, can I pool EntityManagerFactorys for later use?

  4. Any other idea how to create the EntityManagerFactory faster?

Update with more Information and JProfiler profiling

The desktop application can open saved files. Our application document file format constists of 1 SQLite database + and some binary data in a ZIP file. When opening a document, the ZIP gets extracted and the db is opened with Hibernate. The databases all have the same schema, but different data obviously.

It seems that the first time I open a file it takes significantly longer than the following times. I profiled the first and second run with JProfiler and compared the results.

1st Run:

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

.

2nd Run:

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

.

In the Call tree comparison you can see that some methods are significantly faster (DatabaseManager. as starting point):

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

The Hot spot comparison now has the interesting results:

.

ClassLoader.loadClass: -1686ms
XMLSchemaFactory.newSchema: -184ms
ClassFile.<init>: -109ms

I am not sure if it is the loading of Hibernate classes or my Entity classes.

A first improvement would be to create an EMF as soon as the application starts just to initialize all necessary classes (I have an empty db file as a prototype already shipped with my Application). @sharakan thank you for your answer, maybe a DeferredConnectionProvider would already be a solution for this problem.

I will try the DeferredConnectionProvider next! But we might be able to speed it up even further. Do you have any more suggestions?

解决方案

You should be able to do this by implementing your own ConnectionProvider as a decorator around a real ConnectionProvider.

The key observation here is that the ConnectionProvider isn't used until an EntityManager is created (see comment in supportsAggressiveRelease() for a caveat to that). So you can create a DeferredConnectionProvider class, and use it to construct the EntityManagerFactory, but then wait for user input, and do the deferred initialization before actually creating any EntityManager instances. I'm written this as a wrapper around ConnectionPoolImpl, but you should be able to use any other implementation of ConnectionProvider as the base.

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();
    }
}

a rough example of how to use it:

    // 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);

You could put the initial set up of the EntityManagerFactory on a separate thread or something, so that the user never has to wait for it. Then the only thing they'll wait for, after specifying the connection info, is the setting up of the connection pool, which should be fairly quick compared to parsing the object model.

这篇关于Hibernate更快地创建EntityManagerFactory的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆