diff --git a/ruoyi-admin/src/main/resources/application-mybatis.yml b/ruoyi-admin/src/main/resources/application-mybatis.yml
index 4bb5bde..1cdb9f5 100644
--- a/ruoyi-admin/src/main/resources/application-mybatis.yml
+++ b/ruoyi-admin/src/main/resources/application-mybatis.yml
@@ -1,11 +1,11 @@
# MyBatis配置
-# mybatis:
-# # 搜索指定包别名
-# typeAliasesPackage: com.ruoyi.**.domain
-# # 配置mapper的扫描,找到所有的mapper.xml映射文件
-# mapperLocations: classpath*:mapper/**/*Mapper.xml
-# # 加载全局的配置文件
-# configLocation: classpath:mybatis/mybatis-config.xml
+mybatis:
+ # 搜索指定包别名
+ typeAliasesPackage: com.ruoyi.**.domain
+ # 配置mapper的扫描,找到所有的mapper.xml映射文件
+ mapperLocations: classpath*:mapper/**/*Mapper.xml
+ # 加载全局的配置文件
+ configLocation: classpath:mybatis/mybatis-config.xml
# PageHelper分页插件
pagehelper:
diff --git a/ruoyi-framework/pom.xml b/ruoyi-framework/pom.xml
index b092243..4d14a1a 100644
--- a/ruoyi-framework/pom.xml
+++ b/ruoyi-framework/pom.xml
@@ -40,6 +40,18 @@
sharding-jdbc-core
+
+ com.atomikos
+ transactions-spring-boot3-starter
+ 6.0.0
+
+
+
+ javax.transaction
+ jta
+ 1.1
+
+
pro.fessional
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
index 1d4dc1f..c664c33 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
@@ -1,6 +1,7 @@
package com.ruoyi.framework.config;
import java.util.TimeZone;
+
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
@@ -16,7 +17,7 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy;
// 表示通过aop框架暴露该代理对象,AopContext能够访问
@EnableAspectJAutoProxy(exposeProxy = true)
// 指定要扫描的Mapper类的包的路径
-@MapperScan("com.ruoyi.**.mapper")
+@MapperScan(basePackages = "com.ruoyi.**.mapper", sqlSessionTemplateRef = "sqlSessionTemplate")
public class ApplicationConfig
{
/**
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AtomikosConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AtomikosConfig.java
new file mode 100644
index 0000000..b7d3dcc
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AtomikosConfig.java
@@ -0,0 +1,47 @@
+package com.ruoyi.framework.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.jta.JtaTransactionManager;
+
+import com.atomikos.icatch.jta.UserTransactionImp;
+import com.atomikos.icatch.jta.UserTransactionManager;
+
+import jakarta.transaction.TransactionManager;
+import jakarta.transaction.UserTransaction;
+
+/**
+ * JTA 事务配置
+ *
+ * @author ruoyi
+ */
+@Configuration
+public class AtomikosConfig
+{
+ @Bean(name = "userTransaction")
+ public UserTransaction userTransaction() throws Throwable
+ {
+ UserTransactionImp userTransactionImp = new UserTransactionImp();
+ userTransactionImp.setTransactionTimeout(10000);
+ return userTransactionImp;
+ }
+
+ @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
+ public TransactionManager atomikosTransactionManager() throws Throwable
+ {
+ UserTransactionManager userTransactionManager = new UserTransactionManager();
+ userTransactionManager.setForceShutdown(false);
+ return userTransactionManager;
+ }
+
+ @Bean(name = "transactionManager")
+ @DependsOn({ "userTransaction", "atomikosTransactionManager" })
+ public PlatformTransactionManager transactionManager() throws Throwable
+ {
+ UserTransaction userTransaction = userTransaction();
+ TransactionManager atomikosTransactionManager = atomikosTransactionManager();
+ return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
+ }
+}
\ No newline at end of file
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 18a0f4b..b58c17e 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,22 +3,25 @@ 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;
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.pool.DruidDataSource;
-import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceBuilder;
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;
@@ -40,27 +43,69 @@ 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;
+
@Bean
+ @Primary
+ @DependsOn({ "transactionManager" })
@ConfigurationProperties("spring.datasource.druid.master")
- public DataSource masterDataSource(DruidProperties druidProperties) {
- DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
- return druidProperties.dataSource(dataSource);
+ 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(DruidProperties druidProperties) {
- DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
- return druidProperties.dataSource(dataSource);
+ 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;
}
@Bean(name = "dynamicDataSource")
@Primary
public DynamicDataSource dataSource(DataSource masterDataSource) {
Map