我的Java Hibernate应用程序是否使用预准备语句池?

时间:2018-09-04 19:36:19

标签: java hibernate profiler c3p0

我正在使用Hibernate 4.3.11.Final和H2 1.3.172数据库,并且在一个慢速的Linux机器上对应用程序进行性能分析,发现它在特定的SQL INSERT上花了更多的时间,而在其他方面花了更多时间。似乎准备好的语句没有被缓存,因为准备好的语句的数量似乎与执行的语句的数量大致相同。

我已经解释了这种权利(我正在使用Yourkit Profiler)

enter image description here

我的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_size max_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);
}

3 个答案:

答案 0 :(得分:1)

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

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

在大多数情况下,连接越少越好。就您而言,只有一个用户和多个线程,您的计算机不太可能拥有200个CPU来充分利用hibernate.c3p0.max_size=200

答案 1 :(得分:0)

我不认为缓存是问题。如果您每次插入都打开一个新事务,并且始终使用不同的线程插入歌曲表,则可能会因未完成的事务而阻塞自己。多线程很容易导致错误,尤其是在开放式数据库事务中。

答案 2 :(得分:0)

从JDBC 3.0开始,将setMaxStatements(n)设置为n为正数将启用语句池,从而进行缓存。

如果有人在使用Oracle JDBC驱动程序,则可以通过以下任何一种方法来验证缓存

在连接上,

if (conn.getImplicitCachingEnabled())
  System.out.println("\nimplicit caching enabled"); 
else
  System.out.println("\nimplicit caching disabled");

关于声明,

int creationState = stmt.creationState();
switch(creationState) {
case 0:
System.out.println("\nCreation state: new");
break;
case 1:
System.out.println("\nCreation state: from the implicit cache"); 
break;
case 2:
System.out.println("\nCreation state: from the explicit cache"); 
break;
}

参考:Oracle Statement Pooling and Caching