diff --git a/doc/关于多数据源与分布式事务.drawio b/doc/关于多数据源与分布式事务.drawio
new file mode 100644
index 0000000..54ac704
--- /dev/null
+++ b/doc/关于多数据源与分布式事务.drawio
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/resources/application-druid.yml b/ruoyi-admin/src/main/resources/application-druid.yml
index 56ce492..6c5e4ae 100644
--- a/ruoyi-admin/src/main/resources/application-druid.yml
+++ b/ruoyi-admin/src/main/resources/application-druid.yml
@@ -3,20 +3,20 @@ spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
+ dynamic:
+ primary: MASTER
+ datasource:
+ # 主库数据源
+ MASTER:
+ url: jdbc:mysql://127.0.0.1/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ username: root
+ password: 123456
+ # 从库数据源
+ # SLAVE:
+ # url: jdbc:mysql://127.0.0.1/ruoyi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ # username: root
+ # password: 123456
druid:
- # 主库数据源
- master:
- url: jdbc:mysql://127.0.0.1/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
- username: root
- password: 123456
- # 从库数据源
- slave:
- # 从数据源开关/默认关闭
- enabled: false
- url: jdbc:mysql://127.0.0.1/ruoyi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
- username: root
- password: 123456
-
# 初始连接数
initialSize: 5
# 最小连接池数量
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
index 79cd191..39d9d30 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
@@ -6,6 +6,7 @@ import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+
import com.ruoyi.common.enums.DataSourceType;
/**
@@ -19,10 +20,15 @@ import com.ruoyi.common.enums.DataSourceType;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
-public @interface DataSource
-{
+public @interface DataSource {
+
/**
- * 切换数据源名称
+ * 切换数据源名称 - 枚举方式
*/
public DataSourceType value() default DataSourceType.MASTER;
+
+ /**
+ * 切换数据源名称 - 字符串方式
+ */
+ public String name() default "";
}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
index 8c2c9f4..f551e67 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
@@ -1,6 +1,7 @@
package com.ruoyi.framework.aspectj;
import java.util.Objects;
+
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@@ -11,6 +12,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
+
import com.ruoyi.common.annotation.DataSource;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder;
@@ -23,33 +25,31 @@ import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder;
@Aspect
@Order(1)
@Component
-public class DataSourceAspect
-{
+public class DataSourceAspect {
protected Logger logger = LoggerFactory.getLogger(getClass());
@Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"
+ "|| @within(com.ruoyi.common.annotation.DataSource)")
- public void dsPointCut()
- {
+ public void dsPointCut() {
}
@Around("dsPointCut()")
- public Object around(ProceedingJoinPoint point) throws Throwable
- {
+ public Object around(ProceedingJoinPoint point) throws Throwable {
DataSource dataSource = getDataSource(point);
- if (StringUtils.isNotNull(dataSource))
- {
- DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
+ if (StringUtils.isNotNull(dataSource)) {
+ if ("".equals(dataSource.name())) {
+ DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
+ } else {
+ DynamicDataSourceContextHolder.setDataSourceType(dataSource.name());
+ }
+
}
- try
- {
+ try {
return point.proceed();
- }
- finally
- {
+ } finally {
// 销毁数据源 在执行方法之后
DynamicDataSourceContextHolder.clearDataSourceType();
}
@@ -58,12 +58,10 @@ public class DataSourceAspect
/**
* 获取需要切换的数据源
*/
- public DataSource getDataSource(ProceedingJoinPoint point)
- {
+ public DataSource getDataSource(ProceedingJoinPoint point) {
MethodSignature signature = (MethodSignature) point.getSignature();
DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
- if (Objects.nonNull(dataSource))
- {
+ if (Objects.nonNull(dataSource)) {
return dataSource;
}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java
index b8af262..41a79fd 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java
@@ -3,7 +3,6 @@ package com.ruoyi.framework.config;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
-import java.util.Properties;
import javax.sql.DataSource;
@@ -11,20 +10,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
-import org.springframework.core.env.Environment;
import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.util.Utils;
-import com.atomikos.jdbc.AtomikosDataSourceBean;
-import com.ruoyi.common.enums.DataSourceType;
-import com.ruoyi.common.utils.spring.SpringUtils;
-import com.ruoyi.framework.config.properties.DruidProperties;
import com.ruoyi.framework.datasource.DynamicDataSource;
import jakarta.servlet.Filter;
@@ -41,88 +33,20 @@ import jakarta.servlet.ServletResponse;
@Configuration
public class DruidConfig {
- Logger logger = LoggerFactory.getLogger(DruidConfig.class);
-
- public static final String MASTER = DataSourceType.MASTER.name();
-
- public static final String SLAVE = DataSourceType.SLAVE.name();
-
@Autowired
- private DruidProperties druidProperties;
+ DynamicDataSourceProperties dataSourceProperties;
- @Bean
- @Primary
- @DependsOn({ "transactionManager" })
- @ConfigurationProperties("spring.datasource.druid.master")
- public DataSource masterDataSource(Environment env) {
- String prefix = "spring.datasource.druid.master.";
- return getDataSource(env, prefix, MASTER);
- }
-
- @Bean
- @ConfigurationProperties("spring.datasource.druid.slave")
- @DependsOn({ "transactionManager" })
- @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
- public DataSource slaveDataSource(Environment env) {
- String prefix = "spring.datasource.druid.slave.";
- return getDataSource(env, prefix, SLAVE);
- }
-
- protected DataSource getDataSource(Environment env, String prefix, String dataSourceName) {
- Properties prop = build(env, prefix);
- AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
- ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
- // 添加连接池限制
- ds.setMaxPoolSize(50);
- ds.setMinPoolSize(5);
- ds.setBorrowConnectionTimeout(60);
- ds.setUniqueResourceName(dataSourceName);
- ds.setXaProperties(prop);
- return ds;
- }
-
- protected Properties build(Environment env, String prefix) {
- Properties prop = new Properties();
- prop.put("url", env.getProperty(prefix + "url"));
- prop.put("username", env.getProperty(prefix + "username"));
- prop.put("password", env.getProperty(prefix + "password"));
- prop.put("initialSize", druidProperties.getInitialSize());
- prop.put("minIdle", druidProperties.getMinIdle());
- prop.put("maxActive", druidProperties.getMaxActive());
- prop.put("maxWait", druidProperties.getMaxWait());
- prop.put("timeBetweenEvictionRunsMillis", druidProperties.getTimeBetweenEvictionRunsMillis());
- prop.put("minEvictableIdleTimeMillis", druidProperties.getMinEvictableIdleTimeMillis());
- prop.put("maxEvictableIdleTimeMillis", druidProperties.getMaxEvictableIdleTimeMillis());
- prop.put("validationQuery", druidProperties.getValidationQuery());
- prop.put("testWhileIdle", druidProperties.isTestWhileIdle());
- prop.put("testOnBorrow", druidProperties.isTestOnBorrow());
- prop.put("testOnReturn", druidProperties.isTestOnReturn());
- return prop;
- }
+ Logger logger = LoggerFactory.getLogger(DruidConfig.class);
@Bean(name = "dynamicDataSource")
@Primary
- public DynamicDataSource dataSource(DataSource masterDataSource) {
- Map