首页 > 解决方案 > 我的 Java Hibernate 应用程序是否使用准备好的语句池?

问题描述

我正在使用 Hibernate 4.3.11.Final 和 H2 1.3.172 数据库,我在一个缓慢的 linux 机器上分析我的应用程序,发现它在特定 SQL INSERT 上花费的时间比其他任何东西都多。似乎准备好的语句没有被缓存,因为准备好的语句的数量似乎与执行的语句数量大致相同。

我是否正确解释了这一点(我正在使用 Yourkit Profiler)

在此处输入图像描述

我的 HibernateUtil 类配置如下

public static Configuration getInitializedConfiguration()
    {
        Configuration config = new Configuration();

        config.setProperty(Environment.DRIVER,"org.h2.Driver");
        config.setProperty(Environment.URL,"jdbc:h2:"+Db.DBFOLDER+"/"+Db.DBNAME+";FILE_LOCK=SOCKET;MVCC=TRUE;DB_CLOSE_ON_EXIT=FALSE;CACHE_SIZE=50000");
        config.setProperty(Environment.DIALECT,"org.hibernate.dialect.H2Dialect");
        System.setProperty("h2.bindAddress", InetAddress.getLoopbackAddress().getHostAddress());
        config.setProperty("hibernate.connection.username","jaikoz");
        config.setProperty("hibernate.connection.password","jaikoz");
        config.setProperty("hibernate.c3p0.numHelperThreads","10");
        config.setProperty("hibernate.c3p0.min_size","20");
        //Consider that if we have lots of busy threads waiting on next stages could we possibly have alot of active
        //connections.
        config.setProperty("hibernate.c3p0.max_size","200");
        config.setProperty("hibernate.c3p0.timeout","300");
        config.setProperty("hibernate.c3p0.maxStatementsPerConnection","50");
        config.setProperty("hibernate.c3p0.idle_test_period","3000");
        config.setProperty("hibernate.c3p0.acquireRetryAttempts","10");
        addEntitiesToConfig(config);
        return config;
    }

我想知道我是否配置不正确,特别令人困惑的是,c3po 文档在某些参数的名称方面确实与 Hibernate 配置完全结合。

即它是max_sizemax_pool_size

它是一个单用户多线程应用程序,理想情况下,我希望在应用程序期间缓存所有准备好的语句,因为只有大约 50 个不同的语句。

正如我每次做的那样

session = HibernateUtil.beginTransaction();

这将从池中获得一个连接,并且如果该特定连接先前已准备好现在需要的语句,则它可以使用该准备好的语句而无需编译新的语句。

如果准备好的语句不存在,则准备好。

如果这个连接已经有 50 个准备好的语句,那么最旧的语句将被丢弃。

这个占用更多时间的特定查询如下使用

public static void saveMatchedToRelease(Session session,Integer reportId, Integer recNo, SongFieldKey songFieldKey, SongChangeType type, String original, String edited)
{
    SongChanges sc = new SongChanges();
    sc.setReportId(reportId);
    sc.setRecNo(recNo);
    sc.setField(songFieldKey);
    sc.setType(type);
    sc.setOriginalValue(original);
    sc.setNewValue(edited);
    session.save(sc);
}

标签: javahibernateprofilerc3p0

解决方案


在 H2 中,准备好的语句在连接级别缓存。有hibernate.c3p0.max_size=200可能您有如此多的打开连接,以至于每次用户执行操作时,他都会获得不同的 H2 连接。

与其他 RDBMS 相比,本地内存 H2 具有最小的连接成本。尝试移除 C3P0 并使用单个 H2 连接进行测试。这应该确认准备好的语句被 JDBC 驱动程序缓存。

在大多数情况下,连接越少越好。在您的情况下,对于单个用户和多个线程,您的机器不太可能有 200 个 CPU 来充分利用hibernate.c3p0.max_size=200.


推荐阅读