項目中常常會出現須要同時鏈接兩個數據源的狀況,這裏基於MyBatis來配置兩個數據源,並演示如何切換不一樣的數據源。java
經過自定義註解+AOP的方式,來簡化這種數據源的切換操做。mysql
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <druid.version>1.1.2</druid.version> <mysql-connector.version>8.0.7-dmr</mysql-connector.version> <mybatis-plus.version>2.1.8</mybatis-plus.version> <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <!-- MyBatis plus加強和springboot的集成--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>${mybatis-plus.version}</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatisplus-spring-boot-starter</artifactId> <version>${mybatisplus-spring-boot-starter.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.3</version> <scope>test</scope> </dependency> </dependencies>
初始化數據庫
這裏咱們須要建立兩個數據庫,初始化腳本以下:spring
-- -------------------------------------如下是pos業務庫開始------------------------------------------- CREATE DATABASE IF NOT EXISTS pos default charset utf8 COLLATE utf8_general_ci; SET FOREIGN_KEY_CHECKS=0; USE pos; -- 後臺管理用戶表 DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主鍵ID', `username` VARCHAR(32) NOT NULL COMMENT '帳號', `name` VARCHAR(16) DEFAULT '' COMMENT '名字', `password` VARCHAR(128) DEFAULT '' COMMENT '密碼', `salt` VARCHAR(64) DEFAULT '' COMMENT 'md5密碼鹽', `phone` VARCHAR(32) DEFAULT '' COMMENT '聯繫電話', `tips` VARCHAR(255) COMMENT '備註', `state` TINYINT(1) DEFAULT 1 COMMENT '狀態 1:正常 2:禁用', `created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間', `updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間' ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='後臺管理用戶表'; -- 下面是pos數據庫中的插入數據 INSERT INTO `t_user` VALUES (1,'admin','系統管理員','123456','www', '17890908889', '系統管理員', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12'); INSERT INTO `t_user` VALUES (2,'aix','張三','123456','eee', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12'); -- -------------------------------------如下biz業務庫開始------------------------------------------- CREATE DATABASE IF NOT EXISTS biz default charset utf8 COLLATE utf8_general_ci; SET FOREIGN_KEY_CHECKS=0; USE biz; -- 後臺管理用戶表 DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主鍵ID', `username` VARCHAR(32) NOT NULL COMMENT '帳號', `name` VARCHAR(16) DEFAULT '' COMMENT '名字', `password` VARCHAR(128) DEFAULT '' COMMENT '密碼', `salt` VARCHAR(64) DEFAULT '' COMMENT 'md5密碼鹽', `phone` VARCHAR(32) DEFAULT '' COMMENT '聯繫電話', `tips` VARCHAR(255) COMMENT '備註', `state` TINYINT(1) DEFAULT 1 COMMENT '狀態 1:正常 2:禁用', `created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間', `updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間' ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='後臺管理用戶表'; -- 下面是biz數據庫中的插入數據 INSERT INTO `t_user` VALUES (1,'admin1','系統管理員','123456','www', '17890908889', '系統管理員', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12'); INSERT INTO `t_user` VALUES (2,'aix1','張三','123456','eee', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');
能夠看到我建立了兩個數據庫pos和biz,同時還初始化了用戶表,並分別插入兩條初始數據。注意用戶名數據不相同。sql
配置文件
接下來修改application.yml配置文件,以下:數據庫
################### 自定義配置 ################### xncoding: muti-datasource-open: true #是否開啓多數據源(true/false) ################### mybatis-plus配置 ################### mybatis-plus: mapper-locations: classpath*:com/xncoding/pos/common/dao/repository/mapping/*.xml typeAliasesPackage: > com.xncoding.pos.common.dao.entity global-config: id-type: 0 # 0:數據庫ID自增 1:用戶輸入id 2:全局惟一id(IdWorker) 3:全局惟一ID(uuid) db-column-underline: false refresh-mapper: true configuration: map-underscore-to-camel-case: true cache-enabled: true #配置的緩存的全局開關 lazyLoadingEnabled: true #延時加載的開關 multipleResultSetsEnabled: true #開啓的話,延時加載一個屬性時會加載該對象所有屬性,不然按需加載屬性 #默認數據源 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/pos?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8 username: root password: 123456 #多數據源 biz: datasource: url: jdbc:mysql://127.0.0.1:3306/biz?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8 username: root password: 123456
添加了一個自定義配置項muti-datasource-open
,用來控制是否開啓多數據源支持。這個配置項後面會用到。 接下來定義MyBatis的配置,最後定義了兩個MySQL數據庫的鏈接信息,一個是pos庫,一個是biz庫。緩存
動態切換數據源
這裏經過Spring的AOP技術實現數據源的動態切換。springboot
多數據源的常量類:mybatis
public interface DSEnum { String DATA_SOURCE_CORE = "dataSourceCore"; //核心數據源 String DATA_SOURCE_BIZ = "dataSourceBiz"; //其餘業務的數據源 }
datasource的上下文,用來存儲當前線程的數據源類型:app
1 public class DataSourceContextHolder { 2 3 private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); 4 5 /** 6 * @param dataSourceType 數據庫類型 7 * @Description: 設置數據源類型 8 */ 9 public static void setDataSourceType(String dataSourceType) { 10 contextHolder.set(dataSourceType); 11 } 12 13 /** 14 * @Description: 獲取數據源類型 15 */ 16 public static String getDataSourceType() { 17 return contextHolder.get(); 18 } 19 20 public static void clearDataSourceType() { 21 contextHolder.remove(); 22 } 23 }
定義動態數據源,繼承AbstractRoutingDataSource
:ide
1 public class DynamicDataSource extends AbstractRoutingDataSource { 2 3 @Override 4 protected Object determineCurrentLookupKey() { 5 return DataSourceContextHolder.getDataSourceType(); 6 } 7 }
接下來自定義一個註解,用來在Service方法上面註解使用哪一個數據源:
1 @Inherited 2 @Retention(RetentionPolicy.RUNTIME) 3 @Target(ElementType.METHOD) 4 public @interface DataSource { 5 6 String name() default ""; 7 }
最後,最核心的AOP類定義:
1 @Aspect 2 @Component 3 @ConditionalOnProperty(prefix = "code", name = "muti-datasource-open", havingValue = "true") 4 public class MultiSourceExAop implements Ordered { 5 6 private static final Logger LOGGER = LoggerFactory.getLogger(MultiSourceExAop.class); 7 8 @Pointcut(value = "@annotation(com.code.springbootmultisource.common.annotation.DataSource)") 9 private void cut() {} 10 11 @Around("cut()") 12 public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { 13 Signature signature = proceedingJoinPoint.getSignature(); 14 MethodSignature methodSignature = null; 15 if (!(signature instanceof MethodSignature)) { 16 throw new IllegalArgumentException("該註解只能用於方法"); 17 } 18 methodSignature = (MethodSignature) signature; 19 Object target = proceedingJoinPoint.getTarget(); 20 Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes()); 21 22 DataSource dataSource = currentMethod.getAnnotation(DataSource.class); 23 if (dataSource != null) { 24 DataSourceContextHolder.setDataSourceType(dataSource.name()); 25 LOGGER.info("數據源設置爲: " + dataSource.name()); 26 } else { 27 DataSourceContextHolder.setDataSourceType(DSEnum.DATA_SOURCE_CORE); 28 LOGGER.info("數據源設置爲: " + DSEnum.DATA_SOURCE_CORE); 29 } 30 try { 31 return proceedingJoinPoint.proceed(); 32 } finally { 33 LOGGER.debug("清空數據源信息!"); 34 DataSourceContextHolder.clearDataSourceType(); 35 } 36 } 37 38 /** 39 * aop的順序要早於spring的事務 40 */ 41 @Override 42 public int getOrder() { 43 return 1; 44 } 45 }
這裏使用到了註解@ConditionalOnProperty,只有當個人配置文件中muti-datasource-open=true的時候註解纔會生效。
另外還有一個要注意的地方,就是order,aop的順序必定要早於spring的事務,這裏我將它設置成1,後面你會看到我將spring事務順序設置成2。
配置類
首先有兩個屬性類:
DruidProperties
鏈接池的屬性類MutiDataSourceProperties
biz數據源的屬性類
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
1 @Component 2 @ConfigurationProperties(prefix = "spring.datasource") 3 public class DruidProperties { 4 5 private String url; 6 7 private String username; 8 9 private String password; 10 11 private String driverClassName = "com.mysql.cj.jdbc.Driver"; 12 13 private Integer initialSize = 10; 14 15 private Integer minIdle = 3; 16 17 private Integer maxActive = 60; 18 19 private Integer maxWait = 60000; 20 21 private Boolean removeAbandoned = true; 22 23 private Integer removeAbandonedTimeout = 180; 24 25 private Integer timeBetweenEvictionRunsMillis = 60000; 26 27 private Integer minEvictableIdleTimeMillis = 300000; 28 29 private String validationQuery = "SELECT 'x'"; 30 31 private Boolean testWhileIdle = true; 32 33 private Boolean testOnBorrow = false; 34 35 private Boolean testOnReturn = false; 36 37 private Boolean poolPreparedStatements = true; 38 39 private Integer maxPoolPreparedStatementPerConnectionSize = 50; 40 41 private String filters = "stat"; 42 43 public void config(DruidDataSource dataSource) { 44 dataSource.setDbType(JdbcConstants.MYSQL); 45 dataSource.setUrl(url); 46 dataSource.setUsername(username); 47 dataSource.setPassword(password); 48 dataSource.setDriverClassName(driverClassName); 49 dataSource.setInitialSize(initialSize); // 定義初始鏈接數 50 dataSource.setMinIdle(minIdle); // 最小空閒 51 dataSource.setMaxActive(maxActive); // 定義最大鏈接數 52 dataSource.setMaxWait(maxWait); // 獲取鏈接等待超時的時間 53 dataSource.setRemoveAbandoned(removeAbandoned); // 超過期間限制是否回收 54 dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超過期間限制多長 55 56 // 配置間隔多久才進行一次檢測,檢測須要關閉的空閒鏈接,單位是毫秒 57 dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); 58 // 配置一個鏈接在池中最小生存的時間,單位是毫秒 59 dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); 60 // 用來檢測鏈接是否有效的sql,要求是一個查詢語句 61 dataSource.setValidationQuery(validationQuery); 62 // 申請鏈接的時候檢測 63 dataSource.setTestWhileIdle(testWhileIdle); 64 // 申請鏈接時執行validationQuery檢測鏈接是否有效,配置爲true會下降性能 65 dataSource.setTestOnBorrow(testOnBorrow); 66 // 歸還鏈接時執行validationQuery檢測鏈接是否有效,配置爲true會下降性能 67 dataSource.setTestOnReturn(testOnReturn); 68 // 打開PSCache,而且指定每一個鏈接上PSCache的大小 69 dataSource.setPoolPreparedStatements(poolPreparedStatements); 70 dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); 71 // 屬性類型是字符串,經過別名的方式配置擴展插件,經常使用的插件有: 72 // 監控統計用的filter:stat 73 // 日誌用的filter:log4j 74 // 防護SQL注入的filter:wall 75 try { 76 dataSource.setFilters(filters); 77 } catch (SQLException e) { 78 e.printStackTrace(); 79 } 80 } 81 82 public String getUrl() { 83 return url; 84 } 85 86 public void setUrl(String url) { 87 this.url = url; 88 } 89 90 public String getUsername() { 91 return username; 92 } 93 94 public void setUsername(String username) { 95 this.username = username; 96 } 97 98 public String getPassword() { 99 return password; 100 } 101 102 public void setPassword(String password) { 103 this.password = password; 104 } 105 106 public String getDriverClassName() { 107 return driverClassName; 108 } 109 110 public void setDriverClassName(String driverClassName) { 111 this.driverClassName = driverClassName; 112 } 113 114 public Integer getInitialSize() { 115 return initialSize; 116 } 117 118 public void setInitialSize(Integer initialSize) { 119 this.initialSize = initialSize; 120 } 121 122 public Integer getMinIdle() { 123 return minIdle; 124 } 125 126 public void setMinIdle(Integer minIdle) { 127 this.minIdle = minIdle; 128 } 129 130 public Integer getMaxActive() { 131 return maxActive; 132 } 133 134 public void setMaxActive(Integer maxActive) { 135 this.maxActive = maxActive; 136 } 137 138 public Integer getMaxWait() { 139 return maxWait; 140 } 141 142 public void setMaxWait(Integer maxWait) { 143 this.maxWait = maxWait; 144 } 145 146 public Integer getTimeBetweenEvictionRunsMillis() { 147 return timeBetweenEvictionRunsMillis; 148 } 149 150 public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) { 151 this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; 152 } 153 154 public Integer getMinEvictableIdleTimeMillis() { 155 return minEvictableIdleTimeMillis; 156 } 157 158 public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) { 159 this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; 160 } 161 162 public String getValidationQuery() { 163 return validationQuery; 164 } 165 166 public void setValidationQuery(String validationQuery) { 167 this.validationQuery = validationQuery; 168 } 169 170 public Boolean getTestWhileIdle() { 171 return testWhileIdle; 172 } 173 174 public void setTestWhileIdle(Boolean testWhileIdle) { 175 this.testWhileIdle = testWhileIdle; 176 } 177 178 public Boolean getTestOnBorrow() { 179 return testOnBorrow; 180 } 181 182 public void setTestOnBorrow(Boolean testOnBorrow) { 183 this.testOnBorrow = testOnBorrow; 184 } 185 186 public Boolean getTestOnReturn() { 187 return testOnReturn; 188 } 189 190 public void setTestOnReturn(Boolean testOnReturn) { 191 this.testOnReturn = testOnReturn; 192 } 193 194 public Boolean getPoolPreparedStatements() { 195 return poolPreparedStatements; 196 } 197 198 public void setPoolPreparedStatements(Boolean poolPreparedStatements) { 199 this.poolPreparedStatements = poolPreparedStatements; 200 } 201 202 public Integer getMaxPoolPreparedStatementPerConnectionSize() { 203 return maxPoolPreparedStatementPerConnectionSize; 204 } 205 206 public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) { 207 this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize; 208 } 209 210 public String getFilters() { 211 return filters; 212 } 213 214 public void setFilters(String filters) { 215 this.filters = filters; 216 } 217 218 public Boolean getRemoveAbandoned() { 219 return removeAbandoned; 220 } 221 222 public void setRemoveAbandoned(Boolean removeAbandoned) { 223 this.removeAbandoned = removeAbandoned; 224 } 225 226 public Integer getRemoveAbandonedTimeout() { 227 return removeAbandonedTimeout; 228 } 229 230 public void setRemoveAbandonedTimeout(Integer removeAbandonedTimeout) { 231 this.removeAbandonedTimeout = removeAbandonedTimeout; 232 } 233 }
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
1 @Component 2 @ConfigurationProperties(prefix = "biz.datasource") 3 public class MutiDataSourceProperties { 4 5 private String url; 6 7 private String username; 8 9 private String password; 10 11 public void config(DruidDataSource dataSource) { 12 dataSource.setUrl(url); 13 dataSource.setUsername(username); 14 dataSource.setPassword(password); 15 } 16 17 public String getUrl() { 18 return url; 19 } 20 21 public void setUrl(String url) { 22 this.url = url; 23 } 24 25 public String getUsername() { 26 return username; 27 } 28 29 public void setUsername(String username) { 30 this.username = username; 31 } 32 33 public String getPassword() { 34 return password; 35 } 36 37 public void setPassword(String password) { 38 this.password = password; 39 } 40 }
而後定義配置類:
1 @Configuration 2 @EnableTransactionManagement(order = 2) 3 @MapperScan(basePackages = {"com.code.springbootmultisource.common.dao.repository"}) 4 public class MybatisPlusConfig { 5 6 @Autowired 7 DruidProperties druidProperties; 8 9 @Autowired 10 MutiDataSourceProperties mutiDataSourceProperties; 11 12 /** 13 * 核心數據源 14 */ 15 private DruidDataSource coreDataSource() { 16 DruidDataSource dataSource = new DruidDataSource(); 17 druidProperties.config(dataSource); 18 return dataSource; 19 } 20 21 /** 22 * 另外一個數據源 23 */ 24 private DruidDataSource bizDataSource() { 25 DruidDataSource dataSource = new DruidDataSource(); 26 druidProperties.config(dataSource); 27 mutiDataSourceProperties.config(dataSource); 28 return dataSource; 29 } 30 31 /** 32 * 單數據源鏈接池配置 33 */ 34 @Bean 35 @ConditionalOnProperty(prefix = "code", name = "muti-datasource-open", havingValue = "false") 36 public DruidDataSource singleDatasource() { 37 return coreDataSource(); 38 } 39 40 41 /** 42 * 多數據源鏈接池配置 43 */ 44 @Bean 45 @ConditionalOnProperty(prefix = "code", name = "muti-datasource-open", havingValue = "true") 46 public DynamicDataSource mutiDataSource() { 47 48 DruidDataSource coreDataSource = coreDataSource(); 49 DruidDataSource bizDataSource = bizDataSource(); 50 51 try { 52 coreDataSource.init(); 53 bizDataSource.init(); 54 } catch (SQLException sql) { 55 sql.printStackTrace(); 56 } 57 58 DynamicDataSource dynamicDataSource = new DynamicDataSource(); 59 HashMap<Object, Object> hashMap = new HashMap<>(); 60 hashMap.put(DSEnum.DATA_SOURCE_CORE, coreDataSource); 61 hashMap.put(DSEnum.DATA_SOURCE_BIZ, bizDataSource); 62 dynamicDataSource.setTargetDataSources(hashMap); 63 dynamicDataSource.setDefaultTargetDataSource(coreDataSource); 64 return dynamicDataSource; 65 } 66 67 }
實體類
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
1 @TableName(value = "t_user") 2 public class User extends Model<User> { 3 4 private static final long serialVersionUID = 1L; 5 6 @TableId(value="id", type= IdType.AUTO) 7 private Integer id; 8 9 private String username; 10 11 private String name; 12 13 private String password; 14 15 private String salt; 16 17 private String phone; 18 19 private String tips; 20 21 private Integer state; 22 23 private Date createdTime; 24 25 private Date updatedTime; 26 27 public static long getSerialVersionUID() { 28 return serialVersionUID; 29 } 30 31 public Integer getId() { 32 return id; 33 } 34 35 public void setId(Integer id) { 36 this.id = id; 37 } 38 39 public String getUsername() { 40 return username; 41 } 42 43 public void setUsername(String username) { 44 this.username = username; 45 } 46 47 public String getName() { 48 return name; 49 } 50 51 public void setName(String name) { 52 this.name = name; 53 } 54 55 public String getPassword() { 56 return password; 57 } 58 59 public void setPassword(String password) { 60 this.password = password; 61 } 62 63 public String getSalt() { 64 return salt; 65 } 66 67 public void setSalt(String salt) { 68 this.salt = salt; 69 } 70 71 public String getPhone() { 72 return phone; 73 } 74 75 public void setPhone(String phone) { 76 this.phone = phone; 77 } 78 79 public String getTips() { 80 return tips; 81 } 82 83 public void setTips(String tips) { 84 this.tips = tips; 85 } 86 87 public Integer getState() { 88 return state; 89 } 90 91 public void setState(Integer state) { 92 this.state = state; 93 } 94 95 public Date getCreatedTime() { 96 return createdTime; 97 } 98 99 public void setCreatedTime(Date createdTime) { 100 this.createdTime = createdTime; 101 } 102 103 public Date getUpdatedTime() { 104 return updatedTime; 105 } 106 107 public void setUpdatedTime(Date updatedTime) { 108 this.updatedTime = updatedTime; 109 } 110 111 @Override 112 protected Serializable pkVal() { 113 return this.id; 114 } 115 116 }
定義DAO
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
1 public interface UserMapper extends BaseMapper<User> { 2 3 }
定義Service
1 @Service 2 public class UserService { 3 4 @Resource 5 private UserMapper userMapper; 6 7 public User findById(Integer id) { 8 return userMapper.selectById(id); 9 } 10 11 @DataSource(name = DSEnum.DATA_SOURCE_BIZ) 12 public User findById1(Integer id) { 13 return userMapper.selectById(id); 14 } 15 }
這裏惟一要說明的就是我在方法findById1()
上面增長了註解@DataSource(name = DSEnum.DATA_SOURCE_BIZ)
,這樣這個方法就會訪問biz數據庫。
注意,不加註解就會訪問默認數據庫pos。
測試
最後編寫一個簡單的測試,我只測試findById()
方法和findById1()
方法,看它們是否訪問的是不一樣的數據源。
1 @RunWith(SpringRunner.class) 2 @SpringBootTest 3 public class SpringbootMultisourceApplicationTests { 4 5 private static final Logger LOGGER = LoggerFactory.getLogger(SpringbootMultisourceApplicationTests.class); 6 7 @Resource 8 private UserService userService; 9 10 @Test 11 public void contextLoads() { 12 13 User user = userService.findById(1); 14 LOGGER.info("核心數據庫user = " + user.getUsername()); 15 16 User user1 = userService.findById1(1); 17 LOGGER.info("biz數據庫user = " + user1.getUsername()); 18 } 19 20 }
顯示結果:
核心數據庫user = admin 數據源設置爲: dataSourceBiz biz數據庫user = admin