SpringBoot多數(shù)據(jù)源的基本配置
配置文件將數(shù)據(jù)源連接信息配置好迷扇,注意配置數(shù)據(jù)源的name屬性不要重復(fù)
-
創(chuàng)建配置類,構(gòu)建DataSource蜓席、DataSourceTransactionManager、SqlSessionFactory厨内、SqlSessionTemplate等對(duì)象祈秕。題主使用的springboot版本為2.2.6请毛,要求在構(gòu)建這些對(duì)象時(shí)添加
@Primary
注解,題主理解的是類似于指定主數(shù)據(jù)源瞭亮。示例代碼如下
package com.demo.config; import com.alibaba.druid.pool.DruidDataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; 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 // 掃描 Mapper 接口并容器管理 @MapperScan(basePackages = Ds1DataSourceConfig.PACKAGE,sqlSessionFactoryRef = "ds1SqlSessionFactory")// public class Ds1DataSourceConfig { // 精確到 firm 目錄,以便跟其他數(shù)據(jù)源隔離 static final String PACKAGE = "com.demo.mapper.ds1"; /**本數(shù)據(jù)源掃描的mapper路徑*/ static final String MAPPER_LOCATION = "classpath:com/demo/mapper/ds1/*.xml"; @Value("${spring.datasource.ds1.url}") private String url; @Value("${spring.datasource.ds1.username}") private String user; @Value("${spring.datasource.ds1.password}") private String password; @Value("${spring.datasource.ds1.driver-class-name}") private String driverClass; /**創(chuàng)建數(shù)據(jù)源*/ @Bean(name = "ds1DataSource") @Primary public DataSource firmDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driverClass); dataSource.setUrl(url); dataSource.setUsername(user); dataSource.setPassword(password); return dataSource; } /**創(chuàng)建事務(wù)管理器*/ @Bean(name = "ds1TransactionManager") @Primary public DataSourceTransactionManager firmTransactionManager() { return new DataSourceTransactionManager(firmDataSource()); } /**創(chuàng)建SessionFactory*/ @Bean(name = "ds1SqlSessionFactory") @Primary public SqlSessionFactory firmSqlSessionFactory() throws Exception { final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(firmDataSource()); //支持屬性使用駝峰的命名,mapper配置不需要寫字段與屬性的配置此洲,會(huì)自動(dòng)映射。 org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); //使用jdbc的getGeneratedKeys獲取數(shù)據(jù)庫(kù)自增主鍵值 configuration.setUseGeneratedKeys(true); //使用列別名替換列名 select user as User configuration.setUseColumnLabel(true); //-自動(dòng)使用駝峰命名屬性映射字段 userId user_id configuration.setMapUnderscoreToCamelCase(true); //打印sql--需要調(diào)試時(shí)打開(kāi) //configuration.setLogImpl(StdOutImpl.class); sessionFactory.setConfiguration(configuration); //設(shè)置mapper配置文件 sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources(Ds1DataSourceConfig.MAPPER_LOCATION)); return sessionFactory.getObject(); } /**創(chuàng)建SqlSessionTemplate*/ @Bean(name = "ds1SqlSessionTemplate") @Primary public SqlSessionTemplate firmSqlSessionTemplate(@Qualifier("ds1SqlSessionFactory") SqlSessionFactory sessionFactory) { return new SqlSessionTemplate(sessionFactory); } }
其余數(shù)據(jù)源配置類似呜师,注意
@Primary
只在一個(gè)數(shù)據(jù)源中配置即可。多數(shù)據(jù)源mapper掃描位置盡量區(qū)分開(kāi) -
創(chuàng)建測(cè)試類進(jìn)行測(cè)試匣掸,這里只貼serviceImpl,mapper以及xml自動(dòng)生成即可
ds1:service
package com.demo.service.Impl; import com.demo.entity.ds1.Demo; import com.demo.mapper.ds1.DemoMapper; import com.demo.service.DemoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; /** * @author zy * @version V1.0 * @date 2022/9/7 17:52 */ @Service public class DemoServiceImpl implements DemoService { @Autowired private DemoMapper demoMapper; //因?yàn)槿执嬖诙鄠€(gè)事務(wù)控制器,這里開(kāi)啟事務(wù)時(shí)需要指定事務(wù)控制器 @Transactional(transactionManager = "idsTransactionManager", rollbackFor = Exception.class) @Override public int insert(Demo demo) { demo.setId(new BigDecimal(66666)); int insert = demoMapper.insert(demo); int s = insert / 0; return insert; } }
ds2:service
package com.demo.service.Impl; import com.demo.entity.ds2.Student; import com.demo.mapper.ds2.StudentMapper; import com.demo.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * @author zy * @version V1.0 * @date 2022/9/7 17:53 */ @Service public class StudentServiceImpl implements StudentService { @Autowired private StudentMapper studentMapper; @Transactional(transactionManager = "ds2TransactionManager", rollbackFor = Exception.class) @Override public int insert(Student student) { student.setId(3L); int insert = studentMapper.insert(student); return insert; } }
testService
package com.demo.service.Impl; import com.demo.entity.ds1.Demo; import com.demo.entity.ds2.Student; import com.demo.service.DemoService; import com.demo.service.StudentService; import com.demo.service.TestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * @author zy * @version V1.0 * @date 2022/9/7 18:10 */ @Service public class TestServiceImpl implements TestService { @Autowired private DemoService demoService; @Autowired private StudentService studentService; @Transactional(rollbackFor = Exception.class) @Override public void testTransactional() { studentService.insert(new Student()); demoService.insert(new Demo()); } }
測(cè)試類
package com.demo; import com.demo.entity.ds1.Demo; import com.demo.entity.ds2.Student; import com.demo.service.DemoService; import com.demo.service.StudentService; import com.demo.service.TestService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.web.WebAppConfiguration; /** * @description: * @author: wzy * @date: 2021/12/24 11:24 * @version: V1.0 */ @RunWith(SpringRunner.class) @SpringBootTest @WebAppConfiguration public class DemoServiceImplTest { @Autowired private TestService testService; @Autowired private DemoService demoService; @Autowired private StudentService studentService; //測(cè)試事務(wù) @Test public void testTransactional() { testService.testTransactional(); } //測(cè)試兩個(gè)數(shù)據(jù)源 @Test public void testInsert() { demoService.insert(new Demo()); studentService.insert(new Student()); } }
執(zhí)行testTransactional會(huì)發(fā)現(xiàn),拋出異常戴差,但是student數(shù)據(jù)沒(méi)有回滾。
多數(shù)據(jù)源的事務(wù)管理
多數(shù)據(jù)源事務(wù)控制需要引入spring-boot-starter-jta-atomikos
暖释,maven依賴如下
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
將上述數(shù)據(jù)源配置類只需要將DataSource創(chuàng)建為XAdDataSource并且使用AtomikosDataSourceBean進(jìn)行管理即可。同時(shí)注掉DataSourceTransactionManager球匕,因?yàn)槲覀兊氖聞?wù)管交由spring管理,不需要為每個(gè)數(shù)據(jù)源指定事務(wù)管理器帖烘。
如下
/**創(chuàng)建數(shù)據(jù)源*/
@Bean(name = "ds1DataSource")
@Primary
public DataSource firmDataSource() throws SQLException {
DruidXADataSource xa = new DruidXADataSource();
xa.setUrl(url);
xa.setUsername(user);
xa.setPassword(password);
xa.setDbType(JdbcUtils.ORACLE);
xa.setDriverClassName(driverClass);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(xa);
xaDataSource.setUniqueResourceName("ds1");
return xaDataSource;
}
/**創(chuàng)建事務(wù)管理器*/
/*@Bean(name = "ds1TransactionManager")
@Primary
public DataSourceTransactionManager firmSqlSessionFactory() {
return new DataSourceTransactionManager(firmDataSource());
}*/
同時(shí)修改service層的事務(wù)注解
@Transactional(rollbackFor = Exception.class)
//@Transactional(transactionManager = "idsTransactionManager", rollbackFor = Exception.class)
@Override
public int insert(Demo demo) {
demo.setId(new BigDecimal(66666));
int insert = demoMapper.insert(demo);
int s = insert / 0;
return insert;
}
// @Transactional(transactionManager = "yzxTransactionManager", rollbackFor = Exception.class)
@Transactional(rollbackFor = Exception.class)
@Override
public int insert(Student student) {
student.setId(3L);
int insert = studentMapper.insert(student);
return insert;
}
再次執(zhí)行測(cè)試類,可以發(fā)現(xiàn)照卦,拋出異常的同時(shí),student也進(jìn)行了回滾.