一.密码服务:公司统一进行数据库密码管理,为了防止密码泄露,会不定时更换密码,服务端就需要获取密码,类似key,value账号类型,首先根据数据库名去密码服务注册一个账号,后面通过这个注册的这个账号去获取密码。
有以下几种方式去实现:
1.定时任务
开启定时任务去监控数据库密码是否更改或者去检查数据源是否有报错信息:
(1)监控数据库密码是否更改:密码服务使用hashMap缓存密码到本地,所以通过获取上次缓存的密码接口和最新的密码接口,通过比较这来两个密码是否相等,不等则调用DruidDataSource中的restart()方法重置数据库连接池;
(2)检查数据源是否有报错信息:获取DruidDataSource中的getLastCreateError()和getLastCreateErrorTime()方法,判断数据源是否发生错误,然后判断是否是10s以内的错误,判断之后再重新获取密码,restart()方法重置数据库连接池
2.自定义sql异常处理类(验证不可用,有待改进,原因:一般我们都会用一些数据库组件如Druid,它们都会去处理数据库基本异常,像密码错误等,所以在外面捕获不到异常信息)
在异常类中判断如果错误码是1045这个错误代码的意思为登录账号的密码错误或者是没有权限,则重新调用密码服务获取密码,然后restart()方法重置数据库连接池;
(1)全局捕获sqlException,
(2)自定义注解和aop切面的方式进行判断:
@Target -注解用于dao层的包即ElementType.PACKAGE: 用于描述包
@AfterThrowing:异常抛出增强,相当于ThrowsAdvice
@After: 最终通知(在目标方法执行后调用,无论目标方法是否出现异常,都会执行),不管是抛出异常或者正常退出都会执行
使用@AfterThrowing或者@After,在其方法中如果有SqlException则调用sql异常处理类去处理
注意:
1.因为restart()不会重新获取设置密码,还需要调用setPassword();
2.已经创建的连接还可以使用,直到连接用完或者失效,连接数以及失效时间都是可以进行配置的。
3.如果使用了Druid则可以重写DruidAbstractDataSource类(直接把依赖包里面的源码按照相同包路径复制过来,src和jar包里面的类路径相同,则会优先加载src下的),经debug发现DruidAbstractDataSource类中createPhysicalConnection方法中会捕获SQLException异常然后抛出到DruidDataSource去处理,所有我们只需要在抛出异常去处理之前重新去获取数据库密码,通过DruidDataSource中的setPassword()更新密码就可以。
在使用过程中有几个问题:
(1)为什么要重写抽象类DruidAbstractDataSource类,而不是重写实现这个抽象类的DruidDataSource
因为重写DruidDataSource比较困难,涉及到的方法比较多,需要全部拿出来重写,而抽象类就不存在这些问题;
(2)
二.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博客