import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionTemplate;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.example.demo.mapper.ds1", sqlSessionTemplateRef = "ds1SqlSessionTemplate")
@EnableConfigurationProperties
public class DataSourceConfig1 {
@Primary
@Bean(name = "ds1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.ds1")
public DataSource ds1DataSource() {
return new DruidDataSource();
}
@Primary
@Bean(name = "ds1TransactionManager")
public DataSourceTransactionManager ds1TransactionManager(@Qualifier("ds1DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Primary
@Bean(name = "ds1SqlSessionFactory")
public SqlSessionFactory ds1SqlSessionFactory(@Qualifier("ds1DataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/ds1/*.xml"));
return sessionFactoryBean.getObject();
}
@Primary
@Bean(name = "ds1SqlSessionTemplate")
public SqlSessionTemplate ds1SqlSessionTemplate(@Qualifier("ds1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
# 第一个数据源
spring.datasource.ds1.url=jdbc:mysql://localhost:3306/db1
spring.datasource.ds1.username=root
spring.datasource.ds1.password=root
spring.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
# Druid 连接池配置
spring.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.ds1.initial-size=5
spring.datasource.ds1.min-idle=5
spring.datasource.ds1.max-active=20
spring.datasource.ds1.max-wait=60000
spring.datasource.ds1.time-between-eviction-runs-millis=60000
spring.datasource.ds1.min-evictable-idle-time-millis=300000
spring.datasource.ds1.validation-query=SELECT 1
spring.datasource.ds1.test-while-idle=true
spring.datasource.ds1.test-on-borrow=false
spring.datasource.ds1.test-on-return=false
spring.datasource.ds1.pool-prepared-statements=true
spring.datasource.ds1.max-pool-prepared-statement-per-connection-size=20
# 第二个数据源
spring.datasource.ds2.url=jdbc:mysql://localhost:3306/db2
spring.datasource.ds2.username=root
spring.datasource.ds2.password=root
spring.datasource.ds2.driver-class-name=com.mysql.cj.jdbc.Driver
# Druid 连接池配置
spring.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.ds2.initial-size=5
spring.datasource.ds2.min-idle=5
spring.datasource.ds2.max-active=20
spring.datasource.ds2.max-wait=60000
spring.datasource.ds2.time-between-eviction-runs-millis=60000
spring.datasource.ds2.min-evictable-idle-time-millis=300000
spring.datasource.ds2.validation-query=SELECT 1
spring.datasource.ds2.test-while-idle=true
spring.datasource.ds2.test-on-borrow=false
spring.datasource.ds2.test-on-return=false
spring.datasource.ds2.pool-prepared-statements=true
spring.datasource.ds2.max-pool-prepared-statement-per-connection-size=20
import com.example.demo.mapper.ds1.UserMapper1;
import com.example.demo.mapper.ds2.UserMapper2;
import com.example.demo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.List;
@Service
public class MultiDataSourceTransactionService {
@Autowired
private UserMapper1 userMapper1;
@Autowired
private UserMapper2 userMapper2;
@Autowired
@org.springframework.beans.factory.annotation.Qualifier("ds1TransactionManager")
private DataSourceTransactionManager ds1TransactionManager;
@Autowired
@org.springframework.beans.factory.annotation.Qualifier("ds2TransactionManager")
private DataSourceTransactionManager ds2TransactionManager;
public void performMultiDataSourceTransaction() {
// 定义事务属性
DefaultTransactionDefinition def1 = new DefaultTransactionDefinition();
def1.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status1 = ds1TransactionManager.getTransaction(def1);
DefaultTransactionDefinition def2 = new DefaultTransactionDefinition();
def2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status2 = ds2TransactionManager.getTransaction(def2);
try {
// 在第一个数据源执行操作
List<User> users1 = userMapper1.getAllUsers();
// 模拟业务逻辑
// userMapper1.insertUser(new User());
// 在第二个数据源执行操作
List<User> users2 = userMapper2.getAllUsers();
// 模拟业务逻辑
// userMapper2.insertUser(new User());
// 提交事务
ds1TransactionManager.commit(status1);
ds2TransactionManager.commit(status2);
} catch (Exception e) {
// 回滚事务
ds1TransactionManager.rollback(status1);
ds2TransactionManager.rollback(status2);
throw new RuntimeException("跨数据源事务执行失败", e);
}
}
}