Spring 的 JdbcClient 创建过多的 Oracle 数据库会话

问题描述 投票:0回答:1

我遇到了 Spring 的 JdbcClient 问题,它似乎在我的 Oracle 数据库中创建了过多的会话。此行为会导致意外的资源消耗和潜在的性能问题。我正在寻求帮助来理解和解决这个问题。

问题描述:

  1. 使用的框架/工具:我使用 Spring Boot 和 JdbcClient 进行数据库交互。
  2. 数据库: Oracle 数据库
  3. 观察: 对于每次执行 JdbcClient 创建数据库会话,应用程序似乎正在创建大量数据库会话达到 4k 个会话,这会影响性能。

这是我的应用程序的片段

@Autowired
 private JdbcClient jdbcClient;

 jdbcClient.sql("query")
            .param("id", id)
             .query(String.class)
             .stream().findFirst().orElseGet(() -> "")

当我使用DriverManagerDataSource连接到oracle数据库时

环境信息:

Spring引导版本:3.2.1 Oracle 数据库版本:19c

当我每次客户端调用时使用 DriverManagerDataSource JdbcClient 时,它将创建会话 当我尝试将数据源从 DriverManagerDataSource 更改为 HikariCP 并设置连接池时 当应用程序启动时在数据库中打开会话,但是当我调用使用 JdbcClient 的端点时,第一个请求会成功,但任何其他请求都会出错并且不会打开太多会话

错误

Caused by: java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30006ms.
    at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:696)
    at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:181)
    at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:146)
    at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:100)
    at org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:160)
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:118)
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:81)
    ... 109 more

我在数据库中看到的内容

会议信息

我认为数据库正在等待 JdbcClient 结束连接,但有问题

更多详情..
主班


    @EnableConfigurationProperties(RsaKeyProperties.class)
    @SpringBootApplication
    @EnableAutoConfiguration
    @EnableEncryptableProperties
    @EnableAsync
    @EnableScheduling
    @EnableCaching
    @PropertySource(name = "EncryptedProperties", value = "classpath:database.properties")
    public class Application 

服务等级


@Service
public class InfoService {
 @Autowired
 private JdbcClient jdbcClient;
public SponsorInformation getInformation(String token, PhoneType phoneType) {
String id = tokenService.decodeToken(token.substring(7)).getSubject();
return jdbcClient.sql("query")
            .param("id", id)
             .query(String.class)
             .stream().findFirst().orElseGet(() -> "");
}

应用程序配置类(使用 hikari 也尝试使用 DriverManagerDataSource )

@Configuration
@PropertySource("classpath:database.properties")
public class AppConfig {

    @Autowired
    Environment environment;

    @Value("${url}")
    private String URL;

    @Value("${dbuser}")
    private String USER;

    @Value("${driver}")
    private String DRIVER;

    @Value("${dbpassword}")
    private String PASSWORD;

    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(URL);
        config.setUsername(USER);
        config.setPassword(PASSWORD);
        config.setDriverClassName(DRIVER);

        return new HikariDataSource(config);
    }
}

应用程序.属性

spring.datasource.hikari.connectionTimeout=60000
spring.datasource.hikari.idleTimeout=-1
spring.datasource.hikari.maxLifetime=-1

spring.datasource.hibernate.connection.characterEncoding=UTF-8
spring.mvc.charset=UTF-8
spring.datasource.oracleucp.min-pool-size=10
spring.datasource.oracleucp.max-pool-size=405
spring.datasource.hikari.maximum-pool-size =105
spring.datasource.hikari.minimum-idle =16
jasypt.encryptor.pool-size=20

数据库.属性

driver=oracle.jdbc.OracleDriver
url= jdbc:oracle:thin:@ip:port/sid?useUnicode=yes&characterEncoding=UTF-8 
dbuser= [database_user]
dbpassword=[encrypted_database_password]
oracle spring-boot session jdbc spring-jdbc
1个回答
0
投票

您正在使用 stream()

 中的 
JdbcClient
 方法。现在,如果您阅读文档,该方法附带一个警告:

结果流,包含映射对象,需要在完全处理后关闭(例如通过 try-with-resources 子句)

如果您不关闭它,它将保持底层

ResultSet
的状态,并且
Statement
Connection
保持打开状态。将您的代码修改为类似这样的内容。

public SponsorInformation getInformation(String token, PhoneType phoneType) {
  String id = tokenService.decodeToken(token.substring(7)).getSubject();
  try (Stream<String> stream =  jdbcClient.sql("query")
            .param("id", id)
             .query(String.class)
             .stream()) {
    return.findFirst().orElseGet(() -> "");
  }
}

这将在使用后关闭

Stream
并释放被阻止的资源。

© www.soinside.com 2019 - 2024. All rights reserved.