下面开始讲解“Springboot动态切换数据源的具体实现与原理分析”的完整攻略。
一. 实现原理分析
1.1. 多数据源的实现方式
在多数据源的实现中,我们不能像单数据源的实现那样,在 application.properties 或 application.yml 中写入数据源的配置信息。我们需要寻找一种实现方式,能够在程序运行期间动态配置数据源信息。
1.2. 动态数据源的实现方式
Springboot 动态切换数据源的实现方式主要依靠AbstractRoutingDataSource。
AbstractRoutingDataSource 是 Spring 中的一个抽象类,可以做到根据某种标识进行切换数据源操作。通过继承 AbstractRoutingDataSource,并重写其中的 determineCurrentLookupKey() 方法,我们可以实现多数据源之间的切换。
1.3. 实现步骤
- 在 pom.xml 中添加相关依赖
多数据源的实现首先需要引入多个数据源实现的依赖包。例如,在下面的示例中我们使用了 druid 和 mysql-connector-java 作为我们的两个数据源。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
- 定义数据源枚举类
在多数据源实现的过程中,我们需要通过枚举类的方式来定义多个数据源信息。枚举类中需要包含数据源的相关信息,例如数据库连接信息、数据库用户名、数据库密码等。
public enum DataSourceEnum {
DS_KEY_MASTER("master", "jdbc:mysql://localhost:3306/test1?characterEncoding=UTF-8&useSSL=false", "root", "root"),
DS_KEY_SLAVE("slave", "jdbc:mysql://localhost:3306/test2?characterEncoding=UTF-8&useSSL=false", "root", "root");
private String key;
private String url;
private String userName;
private String password;
DataSourceEnum(String key, String url, String userName, String password) {
this.key = key;
this.url = url;
this.userName = userName;
this.password = password;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
- 编写 AbstractRoutingDataSource 的子类
在编写 AbstractRoutingDataSource 的子类时,我们需要重写其中的 determineCurrentLookupKey() 这个方法。在这个方法中,我们需要根据具体的场景来确定哪个数据源将被返回。
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDataSourceKey();
}
}
- 编写自定义数据源切换工具类
自定义数据源切换工具类用于在程序运行时实现数据源切换。在这个类中,我们主要是编写了一个切换数据源的方法 switchDataSource(),这个方法会将指定的数据源切换为当前的数据源。
public class DataSourceSwitcher {
private static final ThreadLocal<String> dataSources = new ThreadLocal<>();
public static void setDataSource(String dataSourceKey) {
dataSources.set(dataSourceKey);
}
public static String getDataSource() {
return dataSources.get();
}
public static void clearDataSource() {
dataSources.remove();
}
}
- 编写数据源切换 AOP 拦截器
在进行数据源切换时,我们需要编写一个 AOP 拦截器来切换数据源。在这个拦截器中,我们需要实现在访问数据库之前切换数据源。
@Aspect
@Component
public class DataSourceInterceptor {
@Pointcut("execution(* com.cxy.demo.springbootdemo.controller..*.*(..))")
public void dataSourcePointCut() {
}
@Before("dataSourcePointCut()")
public void dataSourceBeforeHandle(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Class<?> targetClass = joinPoint.getTarget().getClass();
Method method = signature.getMethod();
DataSource dataSourceAnno = method.getAnnotation(DataSource.class);
if (dataSourceAnno == null) {
dataSourceAnno = AnnotationUtils.findAnnotation(targetClass, DataSource.class);
}
if (dataSourceAnno != null) {
String dsId = dataSourceAnno.value();
DataSourceSwitcher.setDataSource(dsId);
}
}
@After("dataSourcePointCut()")
public void after() {
DataSourceSwitcher.clearDataSource();
}
}
二. 实现示例
下面是两个简单的示例代码,主要是演示了在程序运行时如何切换数据源。
2.1. 示例 1:在 Service 层中进行数据源的切换
在这个示例中,我们实现了两个简单的查询操作,并且这两个操作所使用的数据源是不同的。具体的实现过程如下:
- 首先在 application.properties 中配置数据源相关信息,例如:
spring.datasource.master.url=jdbc:mysql://localhost:3306/test1?characterEncoding=UTF-8&useSSL=false
spring.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.master.username=root
spring.datasource.master.password=root
spring.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.slave.url=jdbc:mysql://localhost:3306/test2?characterEncoding=UTF-8&useSSL=false
spring.datasource.slave.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.slave.username=root
spring.datasource.slave.password=root
spring.datasource.slave.type=com.alibaba.druid.pool.DruidDataSource
- 在 Service 层中调用两个方法,获取两个不同的数据源。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
@DataSource("master")
public List<User> getUserListFromMaster() {
return userMapper.getUserList();
}
@Override
@DataSource("slave")
public List<User> getUserListFromSlave() {
return userMapper.getUserList();
}
}
注意:在这里我们使用了注解 @DataSource 来指定具体的数据源。
- 最后,在 Mapper 层中使用 XML 的方式来实现具体的 SQL 操作。
2.2. 示例 2:在 Controller 层中进行数据源的切换
在这个示例中,我们实现一个简单的查询操作,并且我们将数据源的切换放在 Controller 层中进行。具体的实现过程如下:
-
在我们的 application.properties 中配置数据源信息。
-
在 Controller 层中实现具体的查询操作。在这个操作中,我们需要指定相关的数据源信息。
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/list")
public List<User> getUserList() {
DataSourceSwitcher.setDataSource("master");
List<User> userList = userService.getUserListFromMaster();
DataSourceSwitcher.clearDataSource();
return userList;
}
}
注意:在这里我们使用了类 DataSourceSwitcher来动态控制数据源的切换。在程序运行的过程中,我们可以在需要切换数据源的地方调用 DataSourceSwitcher.setDataSource() 方法来实现数据源的切换。
三. 参考链接
- SpringBoot实现动态切换数据源(一):https://www.jianshu.com/p/3a3aaff7e6b8
- SpringBoot实现动态切换数据源(二):https://www.jianshu.com/p/ea413ce69d65
- Springboot使用druid实现多数据源配置与动态切换:https://www.jianshu.com/p/1878f12ce88f
以上是“Springboot动态切换数据源的具体实现与原理分析”的完整攻略,如果您还有任何问题,欢迎发出跟进提问。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Springboot动态切换数据源的具体实现与原理分析 - Python技术站