数据源
数据源的意思是“数据库应用程序所使用的数据库或者数据库服务器”;数据源也即数据的来源,是提供某种所需要数据的器件或原始媒体,在数据源中存储了所有建立数据库连接的信息,通过提供正确的数据源名称,可以找到相应的数据库连接。
@DS
我们先来看看这个注解的使用
com.baomidou
dynamic-datasource-spring-boot-starter
3.5.0
修改YML 的配置如下
datasource:
dynamic:
druid:
initial-size: 5
min-idle: 5
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 6000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 60000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
master:
driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
url: jdbc:mysql://localhost:3306/table1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
username: xxxx
password: xxxxx
slave_1:
driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
url: jdbc:mysql://localhost:3306/table2?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
username: xxxx
password: xxxxx
注意这个 dynamic 一定是我们引入的 mybatis 当中的,这个时候,如果我们去使用这个@DS注解的话,那么就可以去切换数据源,比如我们在配置文件中,配置了 master 还有一个 slave_1 的数据源,那么你在使用的时候,可以这样,在我们的方法,或者类上面
@DS("slave_1")
这个注解,你可以使用在你的方法上面,你也可以使用在你的类上面,(一般是用在mapper、service),使用过该注解的方法即可操作到对应的数据源。既然我们知道怎么去使用这个注解了,那么就得来看看这个源码的部分了。
图片
首先mybatis-plus使用com.baomidou.dynamic.datasource.AbstractRoutingDataSource继承 AbstractDataSource接管数据源;
具体实现类(ctrl+alt+b可以查看抽象类或者的具体实现类)为com.baomidou.dynamic.datasource.DynamicRoutingDataSource。项目初始化调用public synchronized void addDataSource(String ds, DataSource dataSource)加载数据源,数据源存进dataSourceMap中。
图片
当我们发送具体的操作请求的时候,进行数据操作时,方法会被com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor拦截
图片
拦截器首先从被拦截的方法或者类(一般@DS注解用于Service,也可用于Mapper和Controller)上寻找@DS注解,获取到@DS注解的值后将其存入com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;DynamicDataSourceContextHolder使用ThreadLocal存储当前线程的数据源名。
进行数据操作时,会调用org.springframework.jdbc.datasource.getConnection()方法;
getConnection()方法最终调用了com.baomidou.dynamic.datasource.AbstractRoutingDataSource的getConnection()方法;
数据操作完成后,方法返回第二步中的拦截器,执行DynamicDataSourceContextHolder.poll();清除掉此次Threadlocal中的数据源,避免影响后续数据操作。
但是还有一个问题了,那就是不可在事务中切换数据库,保证事务需要方法使用同一连接,使用@DS(dataSourceOne)方法调用@DS(dataSourceTwo)无法切换连接,会导致方法报错。