[spring boot]多数据源

1,250 阅读5分钟

该主题概念

谈到数据源不陌生,中小型项目中偶尔也会遇到需要配置多数据源的问题。配置多数据源的核心在于如何配置,怎么让他加载,自己又是怎么区分。在开始之前,简单的介绍下实现的思路,spring boot的数据源默认加载方式肯定是不可行的,所以我们需要将默认加载数据源给注销掉,而自己配置数据源的重点在于你需要知道数据源配置在哪里。

多数据源demo

这里创建一个简单的spring boot项目即可。源码地址在最下方

注销默认配置

项目创建好了之后,在application启动类里,注销掉默认的数据源加载。

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) // 去除数据库自动加载
public class AccessingMultiDataSourceApplication {
	public static void main(String[] args) {
		SpringApplication.run(AccessingMultiDataSourceApplication.class, args);
	}
}
多数据源配置

application.properties:这里不需多说,数据源的一些基本参数。

spring.datasource.primary.jdbc-url=jdbc:mysql://47.96.30.54:3306/primary
spring.datasource.primary.username=root
spring.datasource.primary.password=
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.second.jdbc-url=jdbc:mysql://47.96.30.54:3306/second
spring.datasource.second.username=root
spring.datasource.second.password=
spring.datasource.second.driver-class-name=com.mysql.cj.jdbc.Driver

DataSourceConfig:这里创建所需的多数据源

package com.example.demo.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
 * Created by 神烦 on 2019/9/4.
 * 因为去掉了数据源自动加载 所有要手动加载数据源
 */
@Configuration
public class DataSourceConfig {
    // 主库
    @Bean(name = "primarySource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource PrimarySource() {
        return DataSourceBuilder.create().build();
    }

    // 从库
    @Bean(name = "secondSource")
    @ConfigurationProperties(prefix = "spring.datasource.second")
    public DataSource SecondSource() {
        return DataSourceBuilder.create().build();
    }
}

primaryDataSource,SecondDataSource:这里配置多数据源mybatis的所需参数

package com.example.demo.config;

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.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
 * Created by 神烦 on 2019/9/6.
 */
@Configuration
@MapperScan(basePackages = {"com.example.demo.primary"}, sqlSessionFactoryRef = "PrimarySqlSessionFactory")  // mapper包basePackages扫描路径 指定sqlSessionFactory
public class PrimaryDBConfig {

    @Autowired
    @Qualifier("primarySource") // 指定名称注入 该注释就是为了区分多个相同Bean不同名称的注入方法
    private DataSource dataSource;


    @Bean // 注入数据源
    @Qualifier("primarySqlSession")
    public SqlSessionFactory PrimarySqlSessionFactory() throws Exception{
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate SqlSessionTemplate1() throws Exception{
        SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(PrimarySqlSessionFactory());
        return sqlSessionTemplate;
    }
}
package com.example.demo.config;

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.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
 * Created by 神烦 on 2019/9/6.
 * 从库的配置和主库差不多 注意的是数据源不要注入错误 和扫描的路径
 */
@Configuration
@MapperScan(basePackages = {"com.example.demo.second"}, sqlSessionFactoryRef = "SecondSqlSessionFactory")  // mapper包basePackages扫描路径 指定sqlSessionFactory
public class SecondDBConfig {

    @Autowired
    @Qualifier("secondSource") // 指定名称注入 该注释就是为了区分多个相同Bean不同名称的注入方法
    private DataSource dataSource;


    @Bean // 注入数据源
    @Qualifier("secondSqlSession")
    public SqlSessionFactory SecondSqlSessionFactory() throws Exception{
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate SqlSessionTemplate2() throws Exception{
        SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(SecondSqlSessionFactory());
        return sqlSessionTemplate;
    }
}
多数据源数据准备

因为demo所以一切从简,我是创建了多个库,相同的表,不同的数据方便测试。

DROP TABLE IF EXISTS `t_test`;
CREATE TABLE `t_test` (
  `ID` bigint(20) NOT NULL COMMENT '主键',
  `NAME` varchar(255) DEFAULT NULL COMMENT '名称',
  `REMARK` varchar(255) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

实体类

package com.example.demo.model;

import lombok.Data;

/**
 * Created by 神烦 on 2019/9/6.
 */
@Data
public class Test {
    private Long id;
    private String name;
    private String remark;
}
dao

根据不同数据源的basePackage到指定路径创建dao

package com.example.demo.primary;

import com.example.demo.model.Test;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

/**
 * Created by 神烦 on 2019/9/6.
 */
@Mapper
public interface IPrimaryDao {

    @Select("select * from t_test")
    Test PrimaryTest();
}

second:

package com.example.demo.second;

import com.example.demo.model.Test;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

/**
 * Created by 神烦 on 2019/9/6.
 */
@Mapper
public interface ISecondDao {

    @Select("select * from t_test")
    Test secondTest();
}
测试

至此,多数据源已经配置完毕,需要注意的点就是配置了,basePackage路径文件的创建,sqlSessionFactory和sqlSessionTemplate的注入引用问题。好了,现在我们来测试一下。

package com.example.demo.controller;

import com.example.demo.primary.IPrimaryDao;
import com.example.demo.second.ISecondDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * Created by 神烦 on 2019/9/6.
 */
@RestController
public class MoreDataSourceController {
    private static Logger logger = LoggerFactory.getLogger(MoreDataSourceController.class);

    @Resource
    private IPrimaryDao primaryDao;
    @Resource
    private ISecondDao secondDao;

    @RequestMapping("/test")
    public Object test() {
        logger.info(primaryDao.PrimaryTest().toString());
        logger.info(secondDao.secondTest().toString());
        return "ok";
    }
}

测试结果:

2019-09-07 14:35:47.190  INFO 5812 --- [           main] .e.d.AccessingMultiDataSourceApplication : Starting AccessingMultiDataSourceApplication on USER-20180705XA with PID 5812 (D:\seestech\accessingMoreDataSource\target\classes started by 神烦 in D:\seestech\accessingMoreDataSource)
2019-09-07 14:35:47.193  INFO 5812 --- [           main] .e.d.AccessingMultiDataSourceApplication : No active profile set, falling back to default profiles: default
2019-09-07 14:35:48.324  INFO 5812 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2019-09-07 14:35:48.350  INFO 5812 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-09-07 14:35:48.351  INFO 5812 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.22]
2019-09-07 14:35:48.482  INFO 5812 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-09-07 14:35:48.482  INFO 5812 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1226 ms
2019-09-07 14:35:49.034  INFO 5812 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-09-07 14:35:49.235  INFO 5812 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-09-07 14:35:49.238  INFO 5812 --- [           main] .e.d.AccessingMultiDataSourceApplication : Started AccessingMultiDataSourceApplication in 2.778 seconds (JVM running for 3.254)
2019-09-07 14:36:05.009  INFO 5812 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-09-07 14:36:05.009  INFO 5812 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2019-09-07 14:36:05.014  INFO 5812 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms
2019-09-07 14:36:05.052  INFO 5812 --- [nio-8080-exec-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2019-09-07 14:36:05.289  INFO 5812 --- [nio-8080-exec-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2019-09-07 14:36:05.341  INFO 5812 --- [nio-8080-exec-2] c.e.d.c.MoreDataSourceController         : Test(id=99999, name=主库, remark=主库数据库)
2019-09-07 14:36:05.341  INFO 5812 --- [nio-8080-exec-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Starting...
2019-09-07 14:36:05.474  INFO 5812 --- [nio-8080-exec-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Start completed.
2019-09-07 14:36:05.489  INFO 5812 --- [nio-8080-exec-2] c.e.d.c.MoreDataSourceController         : Test(id=99999, name=从库, remark=从库数据库)

看可能不是很清楚,照着上面的思路自己搞一下会明白很多,数据库得用自己的咯,我给置空了。

源码下载地址: github.com/Liyinzuo/ac…

如果有错误需要改正地方欢迎指正,谢谢~