一般情况下,我们一个服务最多使用一个数据源,并且拥有一个连接池;

但是不能避免的特殊情况,会使用多个库(不包括分库操作),所以就要配备多个指定的数据源,分别对不同的库进行操作

接下来就开始写代码吧!

数据库准备

分别建立两个不同的库(名字任意,本例子使用:dynamic1和dynamic2),在其中建立不同的表,当然如果你懒得话,可以和我一样,复制粘贴,改个名字就行(针对库),你会发现省了很多事… O(∩_∩)O哈哈~

以下为脚本(我用的是同一个表结构,但是数据要改一下,不然分不清使用结果):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- dynamic1 ----------------------------
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for databaseinfo
-- ----------------------------
DROP TABLE IF EXISTS `databaseinfo`;
CREATE TABLE `databaseinfo` () ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of databaseinfo
-- ----------------------------
INSERT INTO `databaseinfo` VALUES ('1', 'NO.1');

SET FOREIGN_KEY_CHECKS = 1;


-- dynamic2 ----------------------------
INSERT INTO `databaseinfo` VALUES ('1', 'NO.2');

简易目录结构

为了不浪费时间,我直接简化目录结构了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
java:
com.maiyikai.dynamic
|--- config
|--- |--- DataSourceOne.java
|--- |--- DataSourceTwo.java
|--- controller
|--- |--- DynamicDataSourceTestController.java
|--- service
|--- |--- DynamicDataSourceOneService.java
|--- |--- DynamicDataSourceTwoService.java
|--- |--- impl
|--- |--- |--- DynamicDataSourceOneServiceImpl.java
|--- |--- |--- DynamicDataSourceTwoServiceImpl.java
|--- mapper
|--- |--- DynamicTestOne.java
|--- mappers
|--- |--- DynamicTestTwo.java
|--- entity
|--- |--- DatabaseInfo.java
|--- DynamicApplication.java

resources
|--- mapper
|--- |--- dynamicOne.xml
|--- mappers
|--- |--- dynamicTwo.xml
|--- application.yml

需要引入的包 pom.xml

引入的包就是正常连接数据库需要的包,为了使对象更高的输出在控制台,我引入了fastjson

这里使用的Spring Boot2以上版本,在配置的地方会有一些不一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.maiyikai</groupId>
<artifactId>dynamic</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>dynamic</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

application.yml配置

因为连接mysql的包的版本比较高,所以有一些多余的配置要加载数据库连接的URL上

因为使用了Spring Boot2以上版本,所以对url和driver-class更改为: jdbc-url和driver-class-name;否则获取不到对应的连接和驱动名称

因未使用了Druid,所以有一个特性是可以根据jdbc-url自动配置相关的驱动类,所以配置地方我删掉了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
server:
port: 8082

# druid:根据jdbc-url自动配置驱动
# 不使用serverTimezone=UTC:java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
# 不使用useSSL=true:Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
spring:
datasource:
druid:
test1:
jdbc-url: jdbc:mysql://localhost:3306/dynamic1?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true
username: root
password: ********
validationQuery: SELECT 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 28800
testOnBorrow: false
testWhileIdle: true
testOnReturn: false
test2:
jdbc-url: jdbc:mysql://localhost:3306/dynamic2?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true
username: root
password: ********
validationQuery: SELECT 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 28800
testOnBorrow: false
testWhileIdle: true
testOnReturn: false

数据源配置

分别配置两个不同的数据源,并设置其中一个为主数据源,否则会报错

需要对DataSource、SqlSessionFactory、SqlSessionTemplate进行配置,所以

  1. 第一个数据源(DataSourceOne.java)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    /**
    * 必须要有一个主数据源
    */
    @Configuration
    @AutoConfigureBefore(DataSourceAutoConfiguration.class)
    @MapperScan(value = "com.maiyikai.dynamic.mapper", sqlSessionTemplateRef = "sqlSessionTemplate1")
    public class DataSourceOne {

    @Bean("dynamic1DataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.druid.test1")
    public DataSource dynamic1DataSource(){
    return DataSourceBuilder.create().build();
    }

    @Bean("sqlSession1Factory")
    @Primary
    public SqlSessionFactory sqlSession1Factory(@Qualifier("dynamic1DataSource") DataSource dataSource) throws Exception {
    SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(dataSource);
    sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
    return sqlSessionFactoryBean.getObject();
    }

    @Bean("sqlSessionTemplate1")
    @Primary
    public SqlSessionTemplate sqlSessionTemplate1(@Qualifier("sqlSession1Factory")SqlSessionFactory sqlSessionFactory){
    return new SqlSessionTemplate(sqlSessionFactory);
    }
  2. 第二个数据源(DataSourceTwo.java)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    /**
    * 不能与主数据源指定同一个mapper,否则不生效
    */
    @Configuration
    @AutoConfigureBefore(DataSourceAutoConfiguration.class)
    @MapperScan(value = "com.maiyikai.dynamic.mappers", sqlSessionTemplateRef = "sqlSessionTemplate2")
    public class DataSourceTwo {

    @Bean("dynamic1DataSource2")
    @ConfigurationProperties(prefix = "spring.datasource.druid.test2")
    public DataSource dataSource(){
    return DataSourceBuilder.create().build();
    }

    @Bean("sqlSessionFactory2")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamic1DataSource2")DataSource dataSource) throws Exception {
    SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(dataSource);
    sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*.xml"));
    return sqlSessionFactoryBean.getObject();
    }

    @Bean("sqlSessionTemplate2")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory){
    return new SqlSessionTemplate(sqlSessionFactory);
    }
    }

服务类

方法声明为一样的,方便(懒)…O(∩_∩)O哈哈~

接口

只拿一个做演示(DynamicDataSourceOneService.java)

1
2
3
public interface DynamicDataSourceOneService {
DatabaseInfo getDatabaseInfo(String id);
}
实现类
  1. DynamicDataSourceOneServiceImpl.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Service
    public class DynamicDataSourceOneServiceImpl implements DynamicDataSourceOneService {

    @Autowired
    private DynamicTestOne dynamicTestOne;

    @Override
    public DatabaseInfo getDatabaseInfo(String id) {
    return dynamicTestOne.getDatabaseInfoOne(id);
    }
    }
  2. DynamicDataSourceTwoServiceImpl.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Service
    public class DynamicDataSourceTwoServiceImpl implements DynamicDataSourceTwoService {

    @Autowired
    private DynamicTestTwo dynamicTestTwo;

    @Override
    public DatabaseInfo getDatabaseInfo(String id) {
    return dynamicTestTwo.getDatabaseInfoTwo(id);
    }
    }

mapper及xml

因为本人比较勤(hen)奋(lan),所以这里只提供一个

  1. mapper(DynamicTestOne.java)

    1
    2
    3
    4
    public interface DynamicTestOne {

    DatabaseInfo getDatabaseInfoOne(@Param("id")String id);
    }
  2. xml(dynamicOne.xml)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.maiyikai.dynamic.mapper.DynamicTestOne">
    <select id="getDatabaseInfoOne" parameterType="java.lang.String" resultType="com.maiyikai.dynamic.entity.DatabaseInfo">
    select * from databaseinfo where id=#{id}
    </select>
    </mapper>

定义测试接口

准备好了,就要定义接口进行测试了,当然我肯定是选择最简单,最容易访问的方式写访问啦(除了这种方法还可以使用单元测试的方式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Controller
@RequestMapping(value = "/DynamicDataSource")
@ResponseBody
public class DynamicDataSourceTestController {

@Autowired
private DynamicDataSourceOneService dynamicDataSourceOneService;

@Autowired
private DynamicDataSourceTwoService dynamicDataSourceTwoService;

@GetMapping("/getDatabaseInfo/{id}")
public String getDatabaseInfo(@PathVariable("id")String id){
DatabaseInfo databaseInfo1 = dynamicDataSourceOneService.getDatabaseInfo(id);
DatabaseInfo databaseInfo2 = dynamicDataSourceTwoService.getDatabaseInfo(id);
System.err.println("databaseInfo1:==="+JSON.toJSONString(databaseInfo1));
System.err.println("databaseInfo2:==="+JSON.toJSONString(databaseInfo2));
return "true";
}
}

启动类中没有做任何的更改,所以就不展示了

访问接口为:http://localhost:8082/DynamicDataSource/getDatabaseInfo/1(因为数据库准备的时候只准备id为1的数据,所以…)
浏览器正常返回: true
控制台返回:

1
2
databaseInfo1:==={"id":"1","info":"NO.1"}
databaseInfo2:==={"id":"1","info":"NO.2"}

由显示结果可以看出,我们多数据源已经可以正常使用啦

最后更新: 2019年10月12日 20:21

原始链接: https://maiyikai.github.io/2019/04/08/1554706715/

× ~谢谢大爷~
打赏二维码