一.密码服务
公司统一进行数据库密码管理,为了防止密码泄露,会不定时更换密码,服务端就需要获取密码,类似key,value账号类型,首先根据数据库名去密码服务注册一个账号,后面通过这个注册的这个账号去获取密码。
有以下几种方式去实现:
1.定时任务
开启定时任务去监控数据库密码是否更改或者去检查数据源是否有报错信息:
(1)监控数据库密码是否更改:密码服务使用hashMap缓存密码到本地,所以通过获取上次缓存的密码接口和最新的密码接口,通过比较这来两个密码是否相等,不等则调用DruidDataSource中的restart()方法重置数据库连接池;
(2)检查数据源是否有报错信息:获取DruidDataSource中的getLastCreateError()和getLastCreateErrorTime()方法,判断数据源是否发生错误,然后判断是否是10s以内的错误,判断之后再重新获取密码,restart()方法重置数据库连接池
实现如下图:
注意:
.因为restart()不会重新获取设置密码,还需要调用setPassword();
2.自定义sql异常处理类
一般我们都会用一些数据库组件如Druid,它们都会去处理数据库基本异常,像密码错误等
在异常类中判断如果错误码是1045,则重新调用密码服务获取密码,然后restart()方法重置数据库连接池;
如果使用了Druid则可以重写DruidAbstractDataSource类(直接把依赖包里面的源码按照相同包路径复制过来,src和jar包里面的类路径相同,则会优先加载src下的),经debug发现DruidAbstractDataSource类中createPhysicalConnection方法中会捕获SQLException异常然后抛出到DruidDataSource去处理,所有我们只需要在抛出异常去处理之前重新去获取数据库密码,通过DruidDataSource中的setPassword()更新密码就可以。
代码如下
//重写DruidAbstractDataSource类,找到createPhysicalConnection方法,增加下面内容
} catch (SQLException ex) {
//重写密码
setPassword(DruidAccessCheck.handlerSqlPassWordEx(ex));
}
public static String handlerSqlPassWordEx(Throwable ex) {
String password = "";
try {
if (ex instanceof SQLException) {
if (((SQLException) ex).getErrorCode() == 1045) {
//获取密码服务 password = "调用密码服务";
}
}
}
catch (Excetpion e) {
System.out.println(e);
}
return password;
}
注意:
已经创建的连接还可以使用,直到连接用完或者失效,连接数以及失效时间都是可以进行配置的。
在使用过程中有几个问题:
(1)为什么要重写抽象类DruidAbstractDataSource类,而不是重写实现这个抽象类的DruidDataSource
因为重写DruidDataSource比较困难,涉及到的方法比较多,需要全部拿出来重写,而抽象类就不存在这些问题;
3.实现DruidPasswordCallback,动态设置密码
`DruidPasswordCallback` 是一个与 Druid(一个数据库连接池)相关的类,它的作用是在数据库连接过程中提供密码。Druid 是阿里巴巴开源的一个数据库连接池,它提供了强大的监控和扩展功能,能够有效地管理和维护数据库连接。
在 Java 应用程序中使用数据库连接池时,为了安全起见,通常不会将数据库的密码直接硬编码在配置文件中。`DruidPasswordCallback` 允许开发者通过实现这个接口来动态地提供密码,这样可以避免密码泄露的风险。
当应用程序需要连接数据库时,Druid 会调用 `DruidPasswordCallback` 的实现类,通过这个回调接口获取密码,然后使用这个密码来建立数据库连接。这样,密码就可以存储在一个更安全的地方,或者通过其他方式动态生成,提高了系统的安全性。
实现如下:
@Configuration
@PropertySource(value="classpath:sql.properties", encoding ="utf-8")
@ConditionalOnProperty(prefix ="",name="",havingValue="")
public class DataSourceConfig {
@Bean(name={"slave"})
@ConfigurationProperties(prefix ="slave.datasource.druid")
public DataSource slaveDataSource() {
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
//获取密码服务密码
dataSource.setPassword("新密码");
dataSource.setPasswordCallback(new DBPasswordCallback("传参"));
return dataSource;
}
}
public class DBPasswordCallback extends DruidPasswordCallback {
String name = "";
public DBPasswordCallback(String name){
this.name = name;
}
@Override
public void setProperties(Properties properties) {
super.setProperties(properties);
//获取密码服务密码
setPassword("新密码");
}
}
二.mysql多数据源
application.yml中简单配置:
spring:
datasource:
数据库1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url:
username:
DBSourceKey: 获取密码服务的key
数据库2:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url:
username:
DBSourceKey: 获取密码服务的key
其他配置:
#数据库连接配置
#驱动
spring.datasource.driverClassName = com.mysql.jdbc.Driver
#数据库链接
spring.datasource.url = jdbc:mysql://localhost:3306/testdb
#用户名
spring.datasource.username = root
#密码
spring.datasource.password = 123456
#数据库连接池配置
#初始化链接数
spring.datasource.initialSize=5
#最小的空闲连接数
spring.datasource.minIdle=5
#最大的空闲连接数
spring.datasource.maxIdle=20
#最大活动连接数
spring.datasource.maxActive=20
#从池中取连接的最大等待时间,单位ms.
spring.datasource.maxWait=60000
#每XXms运行一次空闲连接回收器
spring.datasource.timeBetweenEvictionRunsMillis=60000
#池中的连接空闲XX毫秒后被回收
spring.datasource.minEvictableIdleTimeMillis=300000
#验证使用的SQL语句
spring.datasource.validationQuery=SELECT 1 FROM DUAL
#指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.
spring.datasource.testWhileIdle=true
#借出连接时不要测试,否则很影响性能
spring.datasource.testOnBorrow=false
#归还连接时执行validationQuery检测连接是否有效,
做了这个配置会降低性能
spring.datasource.testOnReturn=false
#是否缓存preparedStatement,也就是PSCache。
PSCache对支持游标的数据库性能提升巨大,比如说oracle。
在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。
5.5及以上版本有PSCache,建议开启。
spring.datasource.poolPreparedStatements=true
#属性类型是字符串,通过别名的方式配置扩展插件,
常用的插件有:
监控统计用的filter:stat
日志用的filter:log4j
防御sql注入的filter:wall
spring.datasource.filters=stat,wall,log4j
#数据池连接参数
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
多数据源实现,如下图:
三.mongodb多数据源
data:
mongodb:
primary:
dbSource:
dbName:
dbAddress:
dbUsername:
实现,如下图:
基础数据库操作:
问题:Exception in monitor thread while connecting to server localhost:27017
原因:因为springboot会自动配置加载本地默认的配置,所以需要排除掉本地自动配置的;
解决:
1.@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
2.移除之后会报No qualifying bean of type 'com.mongodb.MongoClient'等错误,然后按照上图配置缺什么注入什么,就OK。
四.拓展- spring动态刷新配置
1.使用spring 动态修改数据源需要继承AbstractRoutingDataSource类,实现determineCurrentLookupKey方法就能动态的修改数据源
2.不重启项目动态刷新配置我们需要spring-boot-starter-actuator提供刷新接口,spring-cloud-starter-config提供动态监测注解,具体实现流程可以参考链接:https://www.jianshu.com/p/230af40377cf
Springboot + DruidDataSource 实现不重启项目加载修改后的数据源_IISON的博客-CSDN博客