我遇到了 Spring 的 JdbcClient 问题,它似乎在我的 Oracle 数据库中创建了过多的会话。此行为会导致意外的资源消耗和潜在的性能问题。我正在寻求帮助来理解和解决这个问题。
问题描述:
这是我的应用程序的片段
@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]
您正在使用 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
并释放被阻止的资源。