我每隔 1 分钟就会刷新 Hikari 数据源。我正在使用 spring data JPA 来执行保存操作。但 JPA 指向旧的数据源 bean,我遇到了以下异常。
java.sql.SQLException: HikariDataSource HikariDataSource (hikariConnectionPool0) has been closed.
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:96)
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:269)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:601)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:385)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:756)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
at
这用于关闭数据源。
((HikariDataSource) 数据源).close()
这用于创建新的数据源。
dataSource = new HikariDataSource(config);
如果您的凭据每 1 分钟刷新一次,则不要使用 Spring Boot 自动配置的
DataSource
。这是一个 HikariDataSource
,是一个实际的连接池。关闭和刷新它不起作用,因为您无法重新设置已经存在的引用。另外,重新连接数据库也需要一段时间,其中密码可能已被重置。
而是使用
DriverManagerDataSource
并将其包裹在 UserCredentialsDataSourceAdapter
中。然后每分钟更新 username
中的 password
和 UserCredentialsDataSourceAdapter
。
@Bean
public DriverManagerDataSource driverManagerDataSource(DataSourceProperties props) {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUrl(props.getUrl());
ds.setDriverClassName(props.determineDriverClassName());
return ds;
}
@Bean
@Primary
public UserCredentialsDataSourceAdapter dataSource(DriverManagerDataSource ds) {
UserCredentialsDataSourceAdapter dsa = new UserCredentialsDataSourceAdapter();
dsa.setTargetDataSource(ds);
return dsa;
}
通过此功能,您可以相应地设置
username
和 password
,当需要连接时,它将使用这些。
public class DataSourceUpdater {
private final UserCredentialsDataSourceAdapter dsa;
public DataSourceUpdater(UserCredentialsDataSourceAdapter dsa) {
this.dsa=dsa;
}
public void doIt() {
var username = //obtain new username
var password = //obtain new password
syncronized(dsa) {
dsa.setUsername(username);
dsa.setPassword(password);
}
}
}