springboot2.0整合多数据源配置

在我们的实际项目中,有可能是使用多个数据库(也就是多数据源)的场景,那么在多数据源的场景下,需要怎么配置以及解决事务问题呢?

话不多说,直接上代码:

pom.xml文件配置

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 4     <modelVersion>4.0.0</modelVersion>
 5     <parent>
 6         <groupId>org.springframework.boot</groupId>
 7         <artifactId>spring-boot-starter-parent</artifactId>
 8         <version>2.2.10.RELEASE</version>
 9         <relativePath/>
10     </parent>
11     <groupId>com.wuwu</groupId>
12     <artifactId>cboot</artifactId>
13     <version>0.0.1-SNAPSHOT</version>
14     <name>cboot</name>
15     <description>this project for Spring Boot</description>
16 
17     <properties>
18         <java.version>1.8</java.version>
19     </properties>
20 
21     <dependencies>
22         <dependency>
23             <groupId>org.springframework.boot</groupId>
24             <artifactId>spring-boot-starter-data-jdbc</artifactId>
25         </dependency>
26         <dependency>
27             <groupId>org.springframework.boot</groupId>
28             <artifactId>spring-boot-starter-web</artifactId>
29         </dependency>
30         <!-- mybatis -->
31         <dependency>
32             <groupId>org.mybatis.spring.boot</groupId>
33             <artifactId>mybatis-spring-boot-starter</artifactId>
34             <version>2.0.0</version>
35         </dependency>
36         <dependency>
37             <groupId>org.projectlombok</groupId>
38             <artifactId>lombok</artifactId>
39             <version>1.18.12</version>
40             <scope>provided</scope>
41         </dependency>
42 
43         <dependency>
44             <groupId>mysql</groupId>
45             <artifactId>mysql-connector-java</artifactId>
46             <scope>runtime</scope>
47         </dependency>
48 
49         <dependency>
50             <groupId>ch.qos.logback</groupId>
51             <artifactId>logback-core</artifactId>
52             <version>1.1.3</version>
53         </dependency>
54         <dependency>
55             <groupId>ch.qos.logback</groupId>
56             <artifactId>logback-access</artifactId>
57             <version>1.1.3</version>
58         </dependency>
59         <dependency>
60             <groupId>ch.qos.logback</groupId>
61             <artifactId>logback-classic</artifactId>
62             <version>1.1.3</version>
63         </dependency>
64 
65         <dependency>
66             <groupId>org.springframework.boot</groupId>
67             <artifactId>spring-boot-starter-test</artifactId>
68             <scope>test</scope>
69             <exclusions>
70                 <exclusion>
71                     <groupId>org.junit.vintage</groupId>
72                     <artifactId>junit-vintage-engine</artifactId>
73                 </exclusion>
74             </exclusions>
75         </dependency>
76     </dependencies>
77 
78     <build>
79         <plugins>
80             <plugin>
81                 <groupId>org.springframework.boot</groupId>
82                 <artifactId>spring-boot-maven-plugin</artifactId>
83             </plugin>
84         </plugins>
85     </build>
86 
87 </project>
View Code

 application.properties文件配置

 1 server.port=8090
 2 server.servlet.context-path=/
 3 
 4 #单数据源
 5 #spring.datasource.driverClassName=com.mysql.jdbc.Driver
 6 #spring.datasource.url=jdbc:mysql://localhost:3306/cboot?useUnicode=true&amp;amp;characterEncoding=UTF-8
 7 #spring.datasource.username=root
 8 #spring.datasource.password=root
 9 
10 #多数据源-订单
11 spring.datasource.order.driverClassName=com.mysql.jdbc.Driver
12 spring.datasource.order.jdbc-url=jdbc:mysql://localhost:3306/cboot?useUnicode=true&amp;amp;characterEncoding=UTF-8
13 spring.datasource.order.username=root
14 spring.datasource.order.password=root
15 
16 #多数据源-会员
17 spring.datasource.member.driverClassName=com.mysql.jdbc.Driver
18 spring.datasource.member.jdbc-url=jdbc:mysql://localhost:3306/cboot1?useUnicode=true&amp;amp;characterEncoding=UTF-8
19 spring.datasource.member.username=root
20 spring.datasource.member.password=root
View Code

 注意:多数据源的情况下在连接数据源地址的时,将常用的spring.datasource.url换成spring.datasource.jdbc-url,否则会报jdbcUrl is required with driverClassName的错误,如下图:

会员数据源配置

 1 package com.wuwu.cboot.config;
 2 
 3 import lombok.SneakyThrows;
 4 import org.apache.ibatis.session.SqlSessionFactory;
 5 import org.mybatis.spring.SqlSessionFactoryBean;
 6 import org.mybatis.spring.SqlSessionTemplate;
 7 import org.mybatis.spring.annotation.MapperScan;
 8 import org.springframework.beans.factory.annotation.Qualifier;
 9 import org.springframework.boot.context.properties.ConfigurationProperties;
10 import org.springframework.boot.jdbc.DataSourceBuilder;
11 import org.springframework.context.annotation.Bean;
12 import org.springframework.context.annotation.Configuration;
13 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
14 
15 import javax.sql.DataSource;
16 
17 /**
18  * @Description:会员数据源配置
19  * @author: wph
20  * @Version: 1.0
21  * @date: 2021/1/12
22  */
23 
24 @Configuration
25 @MapperScan(basePackages = "com.wuwu.cboot.member.mapper",sqlSessionTemplateRef = "memberSqlSessionTemplate")
26 public class MemberDataSourceConfig {
27 
28     /**
29      * @Description: 配置会员数据源
30      * @author: wph
31      * @date: 2021/1/15
32      * @return javax.sql.DataSource
33      */
34     @Bean("memberDataSource")
35     @ConfigurationProperties("spring.datasource.member")
36     public DataSource memberDataSource(){
37         return DataSourceBuilder.create().build();
38     }
39 
40     /**
41      * @Description: 创建会员事务管理器
42      * @author: wph
43      * @date: 2021/1/21
44      * @param dataSource
45      * @return org.springframework.jdbc.datasource.DataSourceTransactionManager
46      */
47     @Bean("memberTransactionManager")
48     public DataSourceTransactionManager memberTransactionManager(@Qualifier("memberDataSource") DataSource dataSource){
49         return new DataSourceTransactionManager(dataSource);
50     }
51 
52     /**
53      * @Description: 将会员sqlSessionFactory注入到容器中
54      * @author: wph
55      * @date: 2021/1/13
56      * @param dataSource 
57      * @return org.apache.ibatis.session.SqlSessionFactory
58      */
59     @SneakyThrows(Exception.class)
60     @Bean("memberSqlSessionFactory")
61     public SqlSessionFactory memberSqlSessionFactory(@Qualifier("memberDataSource")DataSource dataSource){
62         SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
63         sqlSessionFactoryBean.setDataSource(dataSource);
64         return sqlSessionFactoryBean.getObject();
65     }
66 
67     /**
68      * @Description: 创建SqlSessionTemplate模板
69      * @author: wph
70      * @date: 2021/1/18
71      * @param sqlSessionFactory
72      * @return org.mybatis.spring.SqlSessionTemplate
73      */
74     @Bean("memberSqlSessionTemplate")
75     public SqlSessionTemplate memberSqlSessionTemplate(@Qualifier("memberSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
76         return new SqlSessionTemplate(sqlSessionFactory);
77     }
78 
79 }
View Code

订单数据源配置

 1 package com.wuwu.cboot.config;
 2 
 3 import lombok.SneakyThrows;
 4 import org.apache.ibatis.session.SqlSessionFactory;
 5 import org.mybatis.spring.SqlSessionFactoryBean;
 6 import org.mybatis.spring.SqlSessionTemplate;
 7 import org.mybatis.spring.annotation.MapperScan;
 8 import org.springframework.beans.factory.annotation.Qualifier;
 9 import org.springframework.boot.context.properties.ConfigurationProperties;
10 import org.springframework.boot.jdbc.DataSourceBuilder;
11 import org.springframework.context.annotation.Bean;
12 import org.springframework.context.annotation.Configuration;
13 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
14 
15 import javax.sql.DataSource;
16 
17 /**
18  * @Description:订单数据源配置
19  * @author: wph
20  * @Version: 1.0
21  * @date: 2021/1/15
22  */
23 @Configuration
24 @MapperScan(basePackages = "com.wuwu.cboot.order.mapper",sqlSessionFactoryRef = "orderSqlSessionFactory")
25 public class OrderDataSourceConfig {
26 
27     /**
28      * @Description: 配置订单数据源
29      * @author: wph
30      * @date: 2021/1/15
31      * @param orderConfig
32      * @return javax.sql.DataSource
33      */
34     @Bean("orderDataSource")
35     @ConfigurationProperties(prefix = "spring.datasource.order")
36     public DataSource orderDataSource(){
37         return DataSourceBuilder.create().build();
38     }
39 
40     /**
41      * @Description: 创建会员事务管理器
42      * @author: wph
43      * @date: 2021/1/21
44      * @param dataSource
45      * @return org.springframework.jdbc.datasource.DataSourceTransactionManager
46      */
47     @Bean("orderTransactionManager")
48     public DataSourceTransactionManager orderTransactionManager(@Qualifier("orderDataSource") DataSource dataSource){
49         return new DataSourceTransactionManager(dataSource);
50     }
51 
52     /**
53      * @Description: 配置session工厂
54      * @author: wph
55      * @date: 2021/1/18
56      * @param dataSource
57      * @return org.apache.ibatis.session.SqlSessionFactory
58      */
59     @SneakyThrows
60     @Bean("orderSqlSessionFactory")
61     public SqlSessionFactory orderSqlSessionFactory(@Qualifier("orderDataSource") DataSource dataSource){
62         SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
63         sqlSessionFactoryBean.setDataSource(dataSource);
64         return sqlSessionFactoryBean.getObject();
65     }
66 
67     /**
68      * @Description: 创建SqlSessionTemplate模板
69      * @author: wph
70      * @date: 2021/1/18
71      * @param sqlSessionFactory
72      * @return org.mybatis.spring.SqlSessionTemplate
73      */
74     @Bean("orderSqlSessionTemplate")
75     public SqlSessionTemplate orderSqlSessionTemplate(@Qualifier("orderSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
76         return new SqlSessionTemplate(sqlSessionFactory);
77     }
78 
79 }
View Code

Controller层

 1 package com.wuwu.cboot.controller;
 2 
 3 import com.wuwu.cboot.service.MemberService;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.web.bind.annotation.RequestMapping;
 6 import org.springframework.web.bind.annotation.RestController;
 7 
 8 /**
 9  * @Description:会员控制层
10  * @author: wph
11  * @Version: 1.0
12  * @date: 2020/10/26
13  */
14 @RestController
15 public class MemberController {
16 
17     @Autowired
18     private MemberService memberService;
19 
20     /**
21      * @Description: 新增会员用户
22      * @author: wph
23      * @date: 2021/1/20
24      * @param age
25      * @param name
26      * @return java.lang.Object
27      */
28     @RequestMapping("/saveMember")
29     public Object saveMember(int age,String name){
30         return memberService.saveMember(age,name);
31     }
32 }
View Code

service层实现

 1 package com.wuwu.cboot.service.impl;
 2 
 3 import com.wuwu.cboot.member.mapper.MemberMapper;
 4 import com.wuwu.cboot.order.mapper.OrderMemberMapper;
 5 import com.wuwu.cboot.service.MemberService;
 6 import org.springframework.stereotype.Service;
 7 import org.springframework.transaction.annotation.Transactional;
 8 
 9 import javax.annotation.Resource;
10 
11 /**
12  * @Description:
13  * @author: wph
14  * @Version: 1.0
15  * @date: 2021/1/12
16  */
17 @Service
18 public class MemberServiceImpl implements MemberService {
19 
20     @Resource
21     private OrderMemberMapper orderMemberMapper;
22     @Resource
23     private MemberMapper memberMapper;
24 
25     @Transactional("memberTransactionManager")
26     public String saveMember(int age,String name){
27         //调用会员接口
28         int i = memberMapper.saveMember(age, name);
29         return i == 1 ? "true" : "false";
30     }
31 }
View Code

如果需要事务的控制,只需要在方法上方加上@Transactional("对应的事务管理器")注解即可(如代码所示),看到这里你可能会有疑问:如果我一个service方法内调用了不同的数据源,事务怎么解决呢?

别急,请继续往下看

mapper层

 1 package com.wuwu.cboot.member.mapper;
 2 
 3 import org.apache.ibatis.annotations.Insert;
 4 import org.apache.ibatis.annotations.Mapper;
 5 
 6 @Mapper
 7 public interface MemberMapper {
 8 
 9     @Insert("insert into member (age,name) values(#{age},#{name})")
10     int saveMember(int age, String name);
11 }
View Code

mapper接口采用了分包结构的形式,分别对应会员数据源MemberDataSourceConfig以及订单数据源OrderDataSourceConfig中的注解MapperScan地址

最后再附上项目结构以及启动类的代码截图

 关于多数据源的配置,文章到此就已结束了。

但是文章提到一个疑问:如果一个service方法内调用了不同的数据源,事务怎么解决呢?我们修改一下MemberServiceImpl类里面的代码

这种情况下呢,就会出现:多数据源分布式事务问题

A服务中调用了B服务的接口,如果A服务执行时报错,那么A服务对应的事务会回滚,B服务不会回滚,那这样子是肯定不行的。

那如何解决“多数据源分布式事务问题”呢?请移步下一篇文章:springboot2.0 解决多数据源分布式事务问题 

原文地址:https://www.cnblogs.com/w-wu/p/14333950.html