9

我在 tomcat lib 文件夹中将 Hikari 与 SQL Server 2016 和 sqljdbc4-2.0.jar 一起使用。

我对 db 资源的配置如下:

<Resource name="jdbc/SQLServerDS" auth="Container" type="javax.sql.DataSource"
              username="uname"
              password="pwd"
              driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
              url="jdbc:sqlserver://server:port;DatabaseName=dbName"
              maxActive="20"
              maxIdle="10"
              validationQuery="select 1" />

我的数据源配置如下:

@Bean(name = "dataSource")
    public DataSource getDataSource() throws NamingException {
        HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(20);
        config.setDataSourceJNDI("java:comp/env/jdbc/SQLServerDS");
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        config.addDataSourceProperty("useServerPrepStmts", "true");
        config.addDataSourceProperty("cacheResultSetMetadata", "true");
        config.addDataSourceProperty("useLocalSessionState", "true");
        config.addDataSourceProperty("cacheServerConfiguration", "true");
        config.addDataSourceProperty("elideSetAutoCommits", "true");
        config.addDataSourceProperty("maintainTimeStats", "false");
        return new TransactionAwareDataSourceProxy(
                new LazyConnectionDataSourceProxy(new HikariDataSource(config)));
    }

我如何知道preparedstatement 缓存是否适用于不同的连接?

我正在使用带有 hibernate v4.3.10.Final 的 Spring 容器管理事务。

另外,为了使缓存起作用,我是否需要启用二级缓存?

4

3 回答 3

9

HikariCP 实际上不支持PreparedStatement 缓存

其他提供 PreparedStatement 缓存。HikariCP 没有。为什么?

它被认为是错误的实现

在池层使用语句缓存是一种反模式,与驱动程序提供的缓存相比,它会对您的应用程序性能产生负面影响。

解释:

在连接池层,PreparedStatements 只能按连接缓存。如果您的应用程序有 250 个经常执行的查询和一个包含 20 个连接的池,则您要求您的数据库保留 5000 个查询执行计划——同样,池必须缓存这么多 PreparedStatement 及其相关的对象图。

大多数主要的数据库 JDBC 驱动程序已经有一个可以配置的语句缓存,包括 PostgreSQL、Oracle、Derby、MySQL、DB2 等等。JDBC 驱动程序在利用数据库特定功能方面处于独特的地位,并且几乎所有缓存实现都能够跨连接共享执行计划。这意味着,您的 250 个经常执行的查询会在数据库中产生恰好 250 个执行计划,而不是内存中的 5000 个语句和相关的执行计划。聪明的实现甚至不在驱动程序级别的内存中保留 PreparedStatement 对象,而只是将新实例附加到现有计划 ID。

如果你接受它,你不应该尝试\期望缓存PreparedStatement

如果拒绝,可以使用C3P0作为连接池

关于hibernate 中的二级缓存,它大多不在连接池中定义,而是使用相关的连接提供者:

HikariCP 现在有一个用于 Hibernate 4.x 的 ConnectionProvider,称为 HikariConnectionProvider

为了在 Hibernate 4.x 中使用 HikariConnectionProvider,请将以下属性添加到您的 hibernate.properties 配置文件中:

hibernate.connection.provider_class=com.zaxxer.hikari.hibernate.HikariConnectionProvider

从 Hibernate 4.3.6 开始,有一个来自 Hibernate 的官方 ConnectionProvider 类,应该使用它来代替 HikariCP 实现。该类被称为org.hibernate.hikaricp.internal.HikariCPConnectionProvider

于 2019-05-28T06:47:19.017 回答
1

正如 user7294900 所解释的,HikariCP 不缓存准备语句。它将此任务委托给驱动程序。

Microsoft 从 v6.3.0-preview 添加了准备好的语句缓存

可以这样激活:

connection.setStatementPoolingCacheSize(10)
connection.setDisableStatementPooling(false)

这是一个很好的解释:

于 2022-02-27T18:58:26.447 回答
0

对于任何寻找 Oracle JDBC 的人,从链接中引用,

尽管 Oracle JDBC 驱动程序在设计时假设启用了隐式缓存,但默认情况下并未启用此功能。要在连接上启用隐式缓存,可以将相应 OracleConnection 对象的implicitCachingEnabled 属性设置为 true,并将 statementCacheSize 属性设置为正整数

要在连接池上启用它,我们需要

connectionPoolObject.setMaxStatements(10);

如果这样做,将为池中的每个连接启用语句缓存

要验证是否启用了缓存,

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

我们甚至可以在语句级别进行验证,

//Checking the creation state of the prepared statement
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;
}

当语句第一次在连接 C1 上执行时,情况 1 为真,如果在同一连接 C1 上再次执行相同的语句,情况 2 为真。

于 2020-04-19T13:38:32.310 回答