Spring Boot JdbcTemplate-禁用语句缓存?

问题描述

我有一个Spring Boot后端,可以使用REST-API与之通信。该后端使用Spring JdbcTemplate连接并执行Postgresql数据库上的查询

我发现了一个问题,其中一个请求在重复10次后变得非常慢。我将问题缩小到使用JdbcTemplate数据库检索数据的代码部分。更具体地说,问题发生在每个tomcat工作线程的第二次迭代中:

[nio-8080-exec-1] --- GET /myresource - Execution time 400 ms
[nio-8080-exec-2] --- GET /myresource - Execution time 300 ms
[nio-8080-exec-3] --- GET /myresource - Execution time 285 ms
...
[io-8080-exec-10] --- GET /myresource - Execution time 200 ms

现在每个tomcat工作者都分别接收和处理了一个请求,这些工作者中的一个工作者下一次收到使用完全相同的查询的相同请求时,执行时间将增加10-15倍:

[nio-8080-exec-1] --- GET /myresource - Execution time 6000 ms
[nio-8080-exec-2] --- GET /myresource - Execution time 5500 ms
[nio-8080-exec-3] --- GET /myresource - Execution time 6700 ms

我尝试使用psql或pgAdmin运行相同的查询,没有问题。这使我相信JdbcTemplate正在以某种方式为每个工作线程缓存查询,并且第二次运行查询时,由于某种原因它会慢很多,但是我不确定。我还尝试过将tomcat更改为码头/下拖,但在那里同样发生了问题,因此我认为这一定与JdbcTemplate有关。

是否可以通过JdbcTemplate禁用这种类型的缓存,或者有什么其他办法可以避免这种行为?

谢谢!

编辑:
我的application.yaml:

spring:
    datasource:
        platform: postgres
        url: my-jdbc-url
        username: my-user
        password: my-password

代码根据请求中的参数动态创建带有WHERE / AND子句的查询,但是相同的请求参数始终会创建相同的查询代码

public List<MyDatatype> runQuery(MyParams params) {
    String sql = createsqlFromParams(params);
    List<Object> params = createParamsList(params);
    return jdbcTemplate.query(sql,params.toArray(),myDatatypeRowMapper());
}

查询最后看起来像这样(使用postGIS函数按坐标之间的距离排序):

SELECT * FROM my_table 
WHERE x IN [1,2,3] 
AND y BETWEEN 0 AND 1000
AND z BETWEEN 0 AND 500
ORDER BY geom <-> other_geom
LIMIT 1000;

编辑2:
按照@ M.Deinum的建议,添加
spring.datasource.hikari.data-source-properties.preparedStatementCacheQueries=0解决了这个问题!

解决方法

假设您在Spring Boot中使用默认连接池HikariCP,则可以使用spring.datasource.hikari.data-source-properties提供其他特定于驱动程序的属性。

要禁用Server Prepared Statements,您需要包括preparedStatementCacheQueries属性并将其值设置为0(默认值为256)。

spring.datasource.hikari.data-source-properties.preparedStatementCacheQueries=0

这将禁用整个缓存,并可能影响应用程序的不同区域。

这些相关的问题herehere似乎暗示您可能要检查磁盘,索引等,而不是禁用查询缓存。