近期因为公司项目的需要,用上了maven和Springboot,对于java开发这块,早闻maven是个好东西,但一直没有去用,感觉用maven帮我们自己做了太多的事情,一个项目跑起来都不知道背后做了些什么,现在想想,可能那个时候脑子进水了吧。

Springboot作为Spring的简约版(我是这么叫的,没有任何依据),将原来Spring需要做的配置文件,改为了注解,提供了大量的***start组件来帮我们做了很多初始化的处理。

但是今天我想要分享的不是maven如何搭建一个helloword的项目,也不是演示Springboot如何入门。这些网上有很多例子,我想我后续也会慢慢整理属于我的一套。今天想分享的是如何用Springboot配置多数据源(dataSource)的问题,之前一直知道Springboot可以很方便的额管理多数据源,当时遇到这个问题的时候,在网上查找了很长时间,也看了看Springboot的官方文档,都没有找到自己想要的解决方案,无奈看了看Spring是如何配置多数据源的,慢慢的有了些思路,废话不说了,开始吧

1.准备:一个maven工程,mysql数据库

2.pom.xml配置

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

3.创建两个数据库company1,company2

-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `userid` int(11) NOT NULL,
  `username` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES ('0', 'Hello World');

company2中创建表t_subject

-- ----------------------------
-- Table structure for t_subject
-- ----------------------------
DROP TABLE IF EXISTS `t_subject`;
CREATE TABLE `t_subject` (
  `subid` int(11) NOT NULL,
  `subname` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`subid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_subject
-- ----------------------------
INSERT INTO `t_subject` VALUES ('0', 'Start');

4.application.properties增加对数据源的配置

#database1 config
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/company1?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
#database2 config
spring.datasource2.driver-class-name=com.mysql.jdbc.Driver
spring.datasource2.url=jdbc:mysql://127.0.0.1:3306/company2?useUnicode=true&characterEncoding=utf-8
spring.datasource2.username=root
spring.datasource2.password=root

5.配置类的实现

首先是ApplicationStart.java

没有其他的意义,只是让它成为程序的入口

@SpringBootApplication(scanBasePackages="springboot.start",excludeName={"springboot.start.db.company1.mapper","springboot.start.db.company2.mapper"})
public class ApplicationStart {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationStart.class, args);
    }
}

数据源的配置,因为有两个数据源,最好是用两个配置类进行初始话,原因后面会提到

第一个数据源:MysqlDataSource1Config

@Configuration
@MapperScan("springboot.start.db.company1.mapper")
public class MysqlDataSource1Config {
    @Bean(name = "primaryDataSource")
    @Primary
    @ConfigurationProperties(prefix="spring.datasource")
    public DataSource dataSource(){
        return DataSourceBuilder.create().build();
    }
    @Bean(name="primarySqlSessionFactory")
    @Primary
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        return sessionFactory.getObject();
    }
}

第二个数据源:MysqlDataSource2Config

@Configuration
@MapperScan("springboot.start.db.company2.mapper")
public class MysqlDataSource2Config {
    @Bean(name = "secondDataSource")
    @ConfigurationProperties(prefix="spring.datasource2")
    public DataSource dataSource(){
        return DataSourceBuilder.create().build();
    }
    @Bean(name = "secondSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        return sessionFactory.getObject();
    }
}

我的整个包层次如下

SpringBoot Mybatis双数据源的配置_数据库

下面来看看DbService是怎么用这两个数据源的

@Service
public class DbService {
    @Autowired
    TUserMapper tUserMapper;
    @Autowired
    TSubjectMapper tSubjectMapper;
    /**查询第一个数据源的表
     * 根据uid查询user
     * @param uid
     * @return
     */
    public TUser selectUserById(int uid){
        TUser tUser = null;
        TUserExample example = new TUserExample();
        Criteria criteria = example.createCriteria();
        criteria.andUseridEqualTo(uid);
        List<TUser> users = tUserMapper.selectByExample(example);
        if(users!=null && users.size()>0){
            tUser = users.get(0);
        }
        return tUser;
    }
    /**
     * 查询第二个数据源的表
     * @param sid
     * @return
     */
    public TSubject selectSubjectById(int sid){
        TSubject subject = null;
        TSubjectExample example = new TSubjectExample();
        example.createCriteria().andSubidEqualTo(sid);
        List<TSubject> subjects = tSubjectMapper.selectByExample(example);
        if(subjects!=null && subjects.size()>0){
            subject = subjects.get(0);
        }
        return subject;
    }
}

是不是很简单,不管怎么说,我来看看测试的情况

SpringBoot Mybatis双数据源的配置_配置文件_02

第二个呢……

SpringBoot Mybatis双数据源的配置_数据库_03

靠出错了,尼玛,这是要打脸的节奏,从异常的意思来看是说程序还是从数据源1中去查的t_subject表,为什么呢?

回到第二个数据源的配置,再看看MapperScan的属性,其中有一个sqlSessionFactoryRef,天哪噜,这个Spring中的xml配置何其的相似啊,于是乎在第二个数据源上加上sqlSessionFactoryRef="secondSqlSessionFactory" (secondSqlSessionFactory在bean注解是做了声明的)

SpringBoot Mybatis双数据源的配置_配置文件_04

至此呢,关于Springboot和mybatis关于双数据源的配置问题,就告一段落了,对于多数据源也适用哦,小菜试过了的


总结:

1.不同数据源的配置,要写在不同的配置类中个,因为MapperScan好像只支持(猜的,有待深入)一个数据源的配置

2.不同数据源对应的mapper,实体类,最好放在不同的包下,在指定MapperScan中的basePackages时,如果两个数据源的包结构出现父子关系,子包的MapperScan好像就不再生效了,如一个数据源的的mapper,实体类放在springboot.datasource包中,第二个数据源的mapper,实体类放在了springboot.datasource.datasource2中,后面那个MapperScan就不会在扫了,这点我没有直接的截图那样的依据,但我有试过不分包的情况,那样只会有一个默认的那个数据源有效(我的理解是,MapperScan应该是有一个处理机制,当遇到basePackages出现包含关系时,将会实现范围大的那个)

3.在多数据源的配置时,注意在默认的那个要加上@primary

4.在非primary配置中,要注意sqlSessionFactoryRef的配置(当然这个只有用mybatis时需要的)


文中涉及的代码可见 https://github.com/yyb0107/springboot.study