前言
动态切换数据源,看到的常用方法,都是采用AOP思想来进行动态切换;最近做的新项目,有操作两个不同库的需求,于是乎就想,既然采用springboot开发,那么会不会有官方的starter或者第三方的starter呢?小编经过一轮spring官网的查看,然而并没有。但是,最后欣然的发现,还是有starter的,只不过是第三方的。来至于com.baomidou
,使用过mybatis框架的,对这个域名应该并不陌生,不多说,这就开始。
使用
1、pom.xml引依赖
天才第一步,导入依赖库,在我们的pom.xml文件中添加如下maven坐标
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.3.5</version>
</dependency>
2、application.yml文件配置
spring:
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
master: # 名称可以自己定义
driver-class-name: com.mysql.cj.jdbc.Driver
username: xxxx
password: xxxx
url: jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
slave: # 名称可以自己定义
driver-class-name: com.mysql.cj.jdbc.Driver
username: xxxx
password: xxxx
url: jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
配置完启动项目,看到如下图的日志打印,说明两个数据源已经注册成功。
配置挺简单,此时就会有疑问,具体使用时是怎么切换呢?莫急,使用也比较简单。
3. 使用@DS(“xxxx”)注解来切换数据源
xxxx:为我们配置在yml文件中名称。
我们在上边配置了一个master和一个slave两个数据源,并且通过primary指定了master为默认数据源,所以在我们不使用@DS注解时,默认走的是mater的数据源。那么注解加在哪里呢,可以加在我们的service类上或者加到我们的mapper接口上都可以。
@Service
@DS("slave")
public class UserServiceimpl implements UserService {
@Autowired
private UserMapper userMapper;
向上边这样,我们只需要加一个@DS("slave)注解,就可以实现数据源的切换,在使用UserMapper的时候,就可以访问slave库中的user表了,是不是很简单~
使用@DS注解的注意事项:
1、@DS注解可以用在类上,也可以用在方法上,并且存在就近原则,也就是说方法上优先类上。
2、如果不使用@DS注解,走默认数据源
3、当使用到service的类上时,在该类中注入的所有Mapper都会使用@DS(“slave”)指定的数据源
4、当使用到service的方法上时,只有方法中的Mapper会走指定的数据源,该方法外的其他方法还是走默认的数据源
情景一:
/**
* @DS()加到类上后方法test01和方法test02()都中分别调用了UserMapper和RoleMapper,
* 此时两个Mapper都是走的slave的数据源,也就是说注解到类上,该类中的所有Mapper都会走slave数据源。
*/
@DS("slave")
@Service
public class demoService{
@Autowired
private UserMapper userMapper;
@Autowired
private RoleMapper roleMapper;
public void test01(){
userMapper.select();
}
public void test02(){
roleMapper.select();
}
}
情景二:
/**
* @DS()加到test02()方法上,此时只有test02()方法的RoleMapper会走salve数据源,
* 而test01()方法中UserMapper会走默认数据源master。
* 或者也可以显式的给test01()指定@DS("master")
*
*/
@Service
public class demoService{
@Autowired
private UserMapper userMapper;
@Autowired
private RoleMapper roleMapper;
//@DS("master")
public void test01(){
userMapper.select();
}
@DS("slave")
public void test02(){
roleMapper.select();
}
}
情景三:
该中情况,不知道各位小伙伴,有没有想过,在test01()方法中调用test02()方法,test02()是否会走slave数据源呢?
/**
* 这种情况的使用,是错误的,因为test01处于master数据源当中,虽然test02()方法指定了slave数据源,
* 但是在处于master数据源中的test01()中调用test02()方法,test02将处于master数据源中,
* 此时test02()方法将抛出异常,找不到表。没有处于正确的数据源当中。
*
*/
@Service
public class demoService{
@Autowired
private UserMapper userMapper;
@Autowired
private RoleMapper roleMapper;
//@DS("master")
public void test01(){
userMapper.select();
test02();
}
@DS("slave")
public void test02(){
roleMapper.select();
}
}
情景四:
将@DS()注解用在持久层,加在Mapper接口上。我比较推荐这样使用
。需要用到的数据源的地方本身来讲,也是持久层,一般来讲,定义一个Mapper接口我们操作的都是一个库中的一张表,或者多表联查。
不会存在跨库的查询。所以@DS加在Mapper上,我们在service层只要调用Mapper就好了,也不用考虑哪个库了。
/**
* 将@DS("slave")加到demoMapper,这样该Mapper所有的方法将走slave的数据源,这样岂不是很酸爽。
* service你随便调就可以了。
* 然后还有肯定有小伙伴,想到,加到方法上不也行么,加到方法上,每一个抽象方法,对应了不同的sql语句,
* 一个Mapper.xmL中两个方法,分别走两个库,功能是没有问题,但是维护起来比较混乱,不推荐使用。
* 最好遵循单一性原则,将两个库的mapper.xml文件分开来管理。
* 在我的工程当中可以将处于不同的文件夹下来做区分也是个不错的处理方式。
*/
@Mapper
@DS("slave")
public interface demoMapper{
public void test01();
public void test02();
}