很久以前寫過一片文章:SpringBoot+Mybatis-多數(shù)據(jù)源動態(tài)切換+動態(tài)加載劫乱,主要描述實現(xiàn)動態(tài)切換數(shù)據(jù)源,用到某個數(shù)據(jù)庫的時候需要自己手動寫代碼切換, 但是最近公司業(yè)務(wù)需要荷腊,需要實現(xiàn)多個數(shù)據(jù)庫的分布式事務(wù),所以就有了本篇文章;注意流程:
(1) 在配置文件中配置數(shù)據(jù)庫連接信息以及對應(yīng)實體類.
(2) 配置多個數(shù)據(jù)庫連接(數(shù)據(jù)源), 核心配置是注解@MapperScan(basePackages = {"com.mybatis.jta.demo.dao.car_impl*"}, sqlSessionTemplateRef = "sqlSessionTemplateCar")
, 掃描自己數(shù)據(jù)庫的dao接口, 使用自己的sqlSessionTemplate
操作數(shù)據(jù)庫,這樣我們在寫代碼的時候就不需要手動切換數(shù)據(jù)庫了.
(3) 配置事務(wù)管理器 .(協(xié)調(diào)多個數(shù)據(jù)源對事務(wù)進(jìn)行提交或回滾)
(4) 編寫代碼獲取spring容器中bean(連接數(shù)據(jù)源bean)
(5) 修改數(shù)據(jù)源bean中的數(shù)據(jù)庫連接url等連接信息(動態(tài)切換數(shù)據(jù)源)
一.準(zhǔn)備
java使用的是JTA方式實現(xiàn)的分布式事務(wù), 如果想搞清楚原理的朋友請查看我的另外一篇文章: JTA分布式事務(wù)
-
版本:重點是
Mybatis
和druid
版本需要如下指定版本揍瑟,因為Mybatis
新版實現(xiàn)了jdbc4.1+
的功能,而Druid
的并沒有實現(xiàn),只是拋出了SQLFeatureNotSupportedException
異常;jdk:1.8 mybatis-spring-boot-starter:1.3.4 druid-spring-boot-starter: 1.1.14 mysql-connector-java: 8.0.11 spring-boot-starter-parent: 2.1.8.RELEASE
-
三個數(shù)據(jù)庫準(zhǔn)備 db_test, db_user, ljyun_512_merchant, 存儲sql語句的地址
1. db_car 數(shù)據(jù)庫有表 tb_message_package_no 2. db_test 數(shù)據(jù)庫有表 tb_user, tb_role 3. ljyun_512_merchant 商戶私有庫
-
pom.xml新增配置
<!--使用阿里的Druid連接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.14</version> </dependency> <!-- mybatis start --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.4</version> </dependency> <!--分布式事務(wù)支持--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jta-atomikos</artifactId> </dependency>
二.a(chǎn)pplication.properties中數(shù)據(jù)庫配置和對應(yīng)連接屬性實體配置
- application.properties中數(shù)據(jù)庫配置
# 數(shù)據(jù)庫配置 car spring.datasource.car.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.car.driverClassName=com.mysql.cj.jdbc.Driver #spring.datasource.car.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.car.url=jdbc:mysql://localhost:3306/db_car?useUnicode=true&characterEncoding=utf8&useSSL\ =false spring.datasource.car.username=root spring.datasource.car.password=123456 spring.datasource.car.initialSize=5 spring.datasource.car.minIdle=5 spring.datasource.car.maxActive=20 spring.datasource.car.maxWait=60000 spring.datasource.car.timeBetweenEvictionRunsMillis=60000 spring.datasource.car.minEvictableIdleTimeMillis=300000 spring.datasource.car.validationQuery=SELECT 1 FROM DUAL spring.datasource.car.testWhileIdle=true spring.datasource.car.testOnBorrow=false spring.datasource.car.testOnReturn=false spring.datasource.car.poolPreparedStatements=true spring.datasource.car.maxPoolPreparedStatementPerConnectionSize=20 spring.datasource.car.filters=stat,wall,log4j spring.datasource.car.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # 數(shù)據(jù)庫配置 test spring.datasource.test.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.test.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.test.url=jdbc:mysql://localhost:3306/db_test?useUnicode=true&characterEncoding=utf8&useSSL=false spring.datasource.test.username=root spring.datasource.test.password=123456 spring.datasource.test.initialSize=5 spring.datasource.test.minIdle=5 spring.datasource.test.maxActive=20 spring.datasource.test.maxWait=60000 spring.datasource.test.timeBetweenEvictionRunsMillis=60000 spring.datasource.test.minEvictableIdleTimeMillis=300000 spring.datasource.test.validationQuery=SELECT 1 FROM DUAL spring.datasource.test.testWhileIdle=true spring.datasource.test.testOnBorrow=false spring.datasource.test.testOnReturn=false spring.datasource.test.poolPreparedStatements=true spring.datasource.test.maxPoolPreparedStatementPerConnectionSize=20 spring.datasource.test.filters=stat,wall,log4j spring.datasource.test.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # 動態(tài)創(chuàng)建的ljyun數(shù)據(jù)庫 spring.datasource.yun.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.yun.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.yun.url=jdbc:mysql://localhost:3306/ljyun_512_merchant?useUnicode=true&characterEncoding=utf8&useSSL\ =false spring.datasource.yun.username=root spring.datasource.yun.password=123456 spring.datasource.yun.initialSize=5 spring.datasource.yun.minIdle=5 spring.datasource.yun.maxActive=20 spring.datasource.yun.maxWait=60000 spring.datasource.yun.timeBetweenEvictionRunsMillis=60000 spring.datasource.yun.minEvictableIdleTimeMillis=300000 spring.datasource.yun.validationQuery=SELECT 1 FROM DUAL spring.datasource.yun.testWhileIdle=true spring.datasource.yun.testOnBorrow=false spring.datasource.yun.testOnReturn=false spring.datasource.yun.poolPreparedStatements=true spring.datasource.yun.maxPoolPreparedStatementPerConnectionSize=20 spring.datasource.yun.filters=stat,wall,log4j spring.datasource.yun.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
- db_car對應(yīng)數(shù)據(jù)庫配置實體代碼位置
- db_test對應(yīng)數(shù)據(jù)庫配置實體代碼位置
- ljyun_512_merchant對應(yīng)數(shù)據(jù)庫配置實體代碼位置
- 其實文件內(nèi)容都是一樣的乍炉,只是文件名不同而已月培;
三.?dāng)?shù)據(jù)源配置(很重要的一個環(huán)節(jié))
- db_car數(shù)據(jù)源配置
DataSourceCarConfig.java
package com.mybatis.jta.demo.config; import com.alibaba.druid.pool.xa.DruidXADataSource; import com.atomikos.jdbc.AtomikosDataSourceBean; 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.BeanUtils; import org.springframework.beans.factory.annotation.Qualifier; 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 javax.sql.DataSource; /** * db_car數(shù)據(jù)源配置 * Create by liangxifeng on 19-9-27 */ @Configuration // 使用注解的方式使用 //@MapperScan(basePackages = {"com.mybatis.jta.demo.mapper.car*"}, sqlSessionTemplateRef = "sqlSessionTemplateCar") @MapperScan(basePackages = {"com.mybatis.jta.demo.dao.car_impl*"}, sqlSessionTemplateRef = "sqlSessionTemplateCar") // // 掃描dao或mapper接口 public class DataSourceCarConfig { //只能在三個數(shù)據(jù)源配置信息中出現(xiàn)一次,表示告訴spring初始化時候優(yōu)先加載哪個數(shù)據(jù)源 @Primary @Bean("dataSourceCarXA") public DruidXADataSource dataSourceXA(DataSourceCarProperties dataSourceCarProperties) { DruidXADataSource dataSource = new DruidXADataSource(); // 使用BeanUtils將數(shù)據(jù)庫連接屬性映射到數(shù)據(jù)源DruidXADataSource的屬性中 //當(dāng)然也可以通過dataSource.setUrl()的方式配置c BeanUtils.copyProperties(dataSourceCarProperties,dataSource); return dataSource; } @Bean(name = "dataSourceCar") public DataSource dataSourceCar(@Qualifier("dataSourceCarXA") DruidXADataSource dataSource){ AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); xaDataSource.setXaDataSource(dataSource); xaDataSource.setUniqueResourceName("dataSourceCar"); return xaDataSource; } @Bean(name = "sqlSessionFactoryCar") public SqlSessionFactory sqlSessionFactoryCar(@Qualifier("dataSourceCar") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setTypeAliasesPackage("com.mybatis.jta.demo.entity.car"); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/car/*Mapper.xml")); return bean.getObject(); } @Bean(name = "sqlSessionTemplateCar") public SqlSessionTemplate sqlSessionTemplateCar( @Qualifier("sqlSessionFactoryCar") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }
- db_test數(shù)據(jù)源配置
DataSourceTestConfig.java
package com.mybatis.jta.demo.config; import com.alibaba.druid.pool.xa.DruidXADataSource; import com.atomikos.jdbc.AtomikosDataSourceBean; 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.BeanUtils; import org.springframework.beans.factory.annotation.Qualifier; 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 javax.sql.DataSource; /** * Description: db_test數(shù)據(jù)源配置 * Create by liangxifeng on 19-9-27 */ @Configuration // 掃描dao或mapper接口 //@MapperScan(basePackages = {"com.mybatis.jta.demo.mapper.test*"}, sqlSessionTemplateRef = "sqlSessionTemplateTest") @MapperScan(basePackages = {"com.mybatis.jta.demo.dao.test_impl*"}, sqlSessionTemplateRef = "sqlSessionTemplateTest") // public class DataSourceTestConfig { @Bean("dataSourceTestXA") public DruidXADataSource dataSourceXA(DataSourceTestProperties dataSourceTestProperties) { DruidXADataSource dataSource = new DruidXADataSource(); BeanUtils.copyProperties(dataSourceTestProperties,dataSource); return dataSource; } @Bean(name = "dataSourceTest") public DataSource dataSourceTest(@Qualifier("dataSourceTestXA") DruidXADataSource dataSource){ AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); xaDataSource.setXaDataSource(dataSource); xaDataSource.setUniqueResourceName("dataSourceTest"); return xaDataSource; } @Bean(name = "sqlSessionFactoryTest") public SqlSessionFactory sqlSessionFactoryTest(@Qualifier("dataSourceTest") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setTypeAliasesPackage("com.mybatis.jta.demo.entity.test"); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/test/*Mapper.xml")); return bean.getObject(); } @Bean(name = "sqlSessionTemplateTest") public SqlSessionTemplate sqlSessionTemplateTest( @Qualifier("sqlSessionFactoryTest") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }
- ljyun_512_merchnat對應(yīng)數(shù)據(jù)源配置
DataSourceYunConfig.java
, 該數(shù)據(jù)源配置暫時連接的是ljyun_512_merchant
數(shù)據(jù)庫恩急,下面會介紹通過參數(shù)動態(tài)修改該數(shù)據(jù)源的數(shù)據(jù)庫連接信息杉畜,也就意味著切換數(shù)據(jù)庫了.package com.mybatis.jta.demo.config; import com.alibaba.druid.pool.xa.DruidXADataSource; import com.atomikos.jdbc.AtomikosDataSourceBean; 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.BeanUtils; import org.springframework.beans.factory.annotation.Qualifier; 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 javax.sql.DataSource; /** * ljyun私有庫數(shù)據(jù)源配置 * Create by liangxifeng on 19-9-27 */ @Configuration // 使用注解的方式使用 //@MapperScan(basePackages = {"com.mybatis.jta.demo.mapper.car*"}, sqlSessionTemplateRef = "sqlSessionTemplateCar") @MapperScan(basePackages = {"com.mybatis.jta.demo.dao.yun_impl*"}, sqlSessionTemplateRef = "sqlSessionTemplateYun") // // 掃描dao或mapper接口 public class DataSourceYunConfig { @Bean("dataSourceYunXA") public DruidXADataSource dataSourceXA(DataSourceYunProperties dataSourceYunProperties) { DruidXADataSource dataSource = new DruidXADataSource(); BeanUtils.copyProperties(dataSourceYunProperties,dataSource); return dataSource; } @Bean(name = "dataSourceYun") public DataSource dataSourceYun(@Qualifier("dataSourceYunXA") DruidXADataSource dataSource){ AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); xaDataSource.setXaDataSource(dataSource); xaDataSource.setUniqueResourceName("dataSourceYun"); return xaDataSource; } @Bean(name = "sqlSessionFactoryYun") public SqlSessionFactory sqlSessionFactoryYun(@Qualifier("dataSourceYun") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setTypeAliasesPackage("com.mybatis.jta.demo.entity.yun"); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources ("classpath:/mapper/yun/*Mapper.xml")); return bean.getObject(); } @Bean(name = "sqlSessionTemplateYun") public SqlSessionTemplate sqlSessionTemplateYun( @Qualifier("sqlSessionFactoryYun") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }
- XA事務(wù)管理器配置類
XATransactionManagerConfig.java
package com.mybatis.jta.demo.config; import com.atomikos.icatch.jta.UserTransactionImp; import com.atomikos.icatch.jta.UserTransactionManager; 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.annotation.EnableTransactionManagement; import org.springframework.transaction.jta.JtaTransactionManager; import javax.transaction.TransactionManager; import javax.transaction.UserTransaction; /** * XA事務(wù)管理器配置類 * Create by liangxifeng on 19-9-27 */ @Configuration @EnableTransactionManagement public class XATransactionManagerConfig { @Bean(name = "userTransaction") public UserTransaction userTransaction() throws Throwable { UserTransactionImp userTransactionImp = new UserTransactionImp(); //userTransactionImp.setTransactionTimeout(10000); return userTransactionImp; } @Bean(name = "atomikosTransactionManager", initMethod="init", destroyMethod = "close") //@Bean(name = "atomikosTransactionManager") 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 { return new JtaTransactionManager(userTransaction(),atomikosTransactionManager()); } }
- 以上配置是基于mybatis配置文件的方式,其實xml和注解方式配置區(qū)別在于數(shù)據(jù)源配置文件中的
@MapperScan
, 注解的方式掃描的是有注解的mapper
接口目錄衷恭,xml方式掃描的是dao
層接口目錄.xml的方式在sqlSessionFactory中有要配置setMapperLocations(xml配置文件路徑)
.- 基于注解方式配置如下:
@MapperScan(basePackages = {"com.mybatis.jta.demo.mapper.car*"}, sqlSessionTemplateRef = "sqlSessionTemplateCar") @Bean(name = "sqlSessionFactoryCar") public SqlSessionFactory sqlSessionFactoryCar(@Qualifier("dataSourceCar") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setTypeAliasesPackage("com.mybatis.jta.demo.entity.car"); return bean.getObject(); }
- 基于xml的配置:
@MapperScan(basePackages = {"com.mybatis.jta.demo.dao.car_impl*"}, sqlSessionTemplateRef = "sqlSessionTemplateCar") @Bean(name = "sqlSessionFactoryCar") public SqlSessionFactory sqlSessionFactoryCar(@Qualifier("dataSourceCar") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setTypeAliasesPackage("com.mybatis.jta.demo.entity.car"); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/car/*Mapper.xml")); return bean.getObject(); }
- 到此除了dao,service等業(yè)務(wù)代碼編寫外此叠,核心配置已經(jīng)完成.業(yè)務(wù)代碼以及單元測試代碼請查看我的代碼庫.單元測試請查看:
TestIndexService.testMessageUser()
方法,單元測試新增db_car.MessagePackageNo
和db_test.User
表數(shù)據(jù),固定數(shù)據(jù)源
随珠;測試代碼位置 - 但是我們公司內(nèi)部灭袁,需要通過外部參數(shù)來連接不同的數(shù)據(jù)庫猬错,也就是本文章中的
ljyun_512_merchant
有N個數(shù)據(jù)庫,比如:ljyun_1_merchant,ljyun_2_merchant,ljyun_3_merchant茸歧,....
倦炒,這就需要我們動態(tài)連接數(shù)據(jù)庫.我的實現(xiàn)方式是通過外部參數(shù)動態(tài)修改spring容器中的ljyun_512_merchant數(shù)據(jù)源
的url,username,password
等屬性.接下來就是動態(tài)修改數(shù)據(jù)源bean屬性方式實現(xiàn)動態(tài)切換數(shù)據(jù)源.
四.兩個工具類配置
-
自定義獲取從容器中獲取bean的工具類
SpringContextUtil
package com.mybatis.jta.demo.util; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * 自定義獲取從容器中獲取bean的工具類 * liangxifeng 2019-10-13 */ @Component public class SpringContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtil.applicationContext = applicationContext; } //獲取applicationContext public static ApplicationContext getApplicationContext() { return applicationContext; } //通過name獲取 Bean. public static Object getBean(String name) { return getApplicationContext().getBean(name); } //通過class獲取Bean. public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } //通過name,以及Clazz返回指定的Bean public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } }
-
動態(tài)修改spring容器數(shù)據(jù)庫連接池bean的url屬性類
SwitchDB.java
package com.mybatis.jta.demo.util; import com.alibaba.druid.pool.xa.DruidXADataSource; import lombok.extern.slf4j.Slf4j; /** * 動態(tài)修改數(shù)據(jù)庫連接池的url屬性類 * Create by liangxifeng on 19-10-13 */ @Slf4j public class SwitchDB { /** * 修改spring容器中私有庫數(shù)據(jù)源url信息 * @param ljyunId 私有庫云編號 */ public static void to(int ljyunId) { //從spring容器中獲取數(shù)據(jù)源 DruidXADataSource dataSource = (DruidXADataSource) SpringContextUtil.getBean("dataSourceYunXA"); try { // 這里需要先關(guān)閉數(shù)據(jù)源,才可以使新修改的數(shù)據(jù)源設(shè)置生效 dataSource.close(); } catch (Exception e) { log.info("關(guān)閉數(shù)據(jù)源失敗,連接url={}",dataSource.getUrl()); e.printStackTrace(); } String preUrl = "jdbc:mysql://localhost:3306/"; String postUrl = "useUnicode=true&characterEncoding=utf8&useSSL=false"; log.info("切換數(shù)據(jù)庫ljyunId="+ljyunId); //修改數(shù)據(jù)源的連接url屬性 dataSource.setUrl(preUrl+"ljyun_"+ljyunId+"_merchant?" +postUrl); } }
-
使用
TestIndexService.testAddUserTags()
方法單元測試软瞎,單元測新增db_test.User和ljyun_1_merchant.app_tag表數(shù)據(jù), 注意事務(wù)存在與測試的service中./** * 單元測試新增db_test.User和ljyun_512_merchant.app_tag表數(shù)據(jù) * 測試動態(tài)修改數(shù)據(jù)源的連接url屬性逢唤,也就意味著切換數(shù)據(jù)庫了 * 在service中啟用事務(wù)注解 */ @Test public void testAddUserTags(){ User user = new User(); user.setCreateTime(null); user.setName("張三"); user.setAge(10); AppTag appTag = new AppTag(); appTag.setTagName("app_name_1"); //appTag.setTagType(1); appTagService.insert(user,appTag); }
appTagService.insert()
中使用SwitchDB.to()
切換數(shù)據(jù)庫/** * 分布式事務(wù)新增操作 * @param user db_test.tb_user實體 * @param appTag 私有庫app_tag實體 */ @Transactional public void insert(User user, AppTag appTag) { user.setCreateTime(null); //新增db_test.tb_user表數(shù)據(jù) userDao.insert(user); //切換為ljyun_1_merchant數(shù)據(jù)庫 SwitchDB.to(1); //ljYun私有庫數(shù)據(jù)庫連接url信息 System.out.println("yun數(shù)據(jù)庫連接url="+((DruidXADataSource) SpringContextUtil.getBean("dataSourceYunXA")).getUrl()); //db_car數(shù)據(jù)庫連接url信息 DruidXADataSource dataSourceCar = (DruidXADataSource) SpringContextUtil.getBean("dataSourceCarXA"); System.out.println("db_car連接url="+dataSourceCar.getUrl()); //db_test數(shù)據(jù)庫連接url信息 DruidXADataSource dataSourceTest = (DruidXADataSource) SpringContextUtil.getBean("dataSourceTestXA"); System.out.println("db_test連接url="+dataSourceTest.getUrl()); //int a = 10/0; //故意異常回滾 //新增私有庫.app_tag表數(shù)據(jù) appTagDao.insert(appTag); //手動回滾事務(wù) //TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); }
-
可以在業(yè)務(wù)代碼中通過如下方式查看自己現(xiàn)在連接數(shù)據(jù)庫的信息:
以下代碼中dataSourceYunXA
就是數(shù)據(jù)源配置文件DataSourceCarConfig.java
中對應(yīng)的bean的名稱.//ljYun私有庫數(shù)據(jù)庫連接url信息 System.out.println("yun數(shù)據(jù)庫連接url="+((DruidXADataSource) SpringContextUtil.getBean("dataSourceYunXA")).getUrl());
五. 錯誤與總結(jié)
- 配置JTA過程出現(xiàn)錯誤, 參考文章
- 最終通過這個配置出來的(基于mybatis注解), git地址;
- 本篇文章的實現(xiàn)方式是mybatis基于xml的,完整代碼地址: https://github.com/liangxifeng833/jta-demo