springboot-multisource

项目中经常会出现需要同时连接两个数据源的情况,这里基于MyBatis来配置两个数据源,并演示如何切换不同的数据源。

通过自定义注解+AOP的方式,来简化这种数据源的切换操作。

<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>

初始化数据库

这里我们需要创建两个数据库,初始化脚本如下:

-- -------------------------------------以下是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,同时还初始化了用户表,并分别插入两条初始数据。注意用户名数据不相同。

配置文件

接下来修改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技术实现数据源的动态切换。

多数据源的常量类:

public interface DSEnum {
    String DATA_SOURCE_CORE = "dataSourceCore";         //核心数据源
    String DATA_SOURCE_BIZ = "dataSourceBiz";            //其他业务的数据源
}

datasource的上下文,用来存储当前线程的数据源类型:

 

 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 :

 

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。

配置类

首先有两个属性类:

  1. DruidProperties 连接池的属性类
  2. MutiDataSourceProperties biz数据源的属性类
  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 }
View Code

 

 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 }
View Code

 

然后定义配置类:

 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 }

 

实体类

  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 }
View Code

 

定义DAO

 

1 public interface UserMapper extends BaseMapper<User> {
2 
3 }
View Code

 

定义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

 

posted @ 2019-03-28 20:35  UniqueColor  阅读(509)  评论(0编辑  收藏  举报