繁体   English   中英

我怎么知道准备好的语句是否被缓存?

[英]How do I know if the prepared statements are cached?

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

我对数据库资源的配置如下:

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

我如何知道准备语句缓存是否适用于不同的连接?

我正在使用 spring 容器管理事务和 hibernate v4.3.10.Final。

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

HikariCP 实际上不支持PreparedStatement 缓存

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

它被认为是错误的实现

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

解释:

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

大多数主要的数据库 JDBC 驱动程序已经有一个可以配置的 Statement 缓存,包括 PostgreSQL、Oracle、Derby、MySQL、DB2 等。 JDBC 驱动程序处于利用数据库特定功能的独特位置,并且几乎所有缓存实现都能够跨连接共享执行计划。 这意味着内存中的 5000 条语句和关联的执行计划不是 5000 条语句,而是 250 个经常执行的查询在数据库中产生 250 个执行计划。 聪明的实现甚至不会在驱动程序级别的内存中保留 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

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

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

它可以像这样激活:

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

这是一个很好的解释:

对于任何寻找 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 将为真。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM