SpringBoot动态数据源(多数据源⾃动切换)
本⽂实现案例场景:
某系统除了需要从⾃⼰的主要数据库上读取和管理数据外,还有⼀部分业务涉及到其他多个数据库,要求可以在任何⽅法上可以灵活指定具体要操作的数据库。
为了在开发中以最简单的⽅法使⽤,本⽂基于注解和AOP的⽅法实现,在spring boot框架的项⽬中,添加本⽂实现的代码类后,只需要配置好数据源就可以直接通过注解使⽤,简单⽅便。
⼀配置⼆使⽤ 1. 启动类注册动态数据源 2. 配置⽂件中配置多个数据源 3. 在需要的⽅法上使⽤注解指定数据源
1、在启动类添加 @Import({DynamicDataSourceRegister.class, MProxyTransactionManagementConfiguration.class})
1@SpringBootApplication
2@Import({DynamicDataSourceRegister.class}) // 注册动态多数据源
3public class SpringBootSampleApplication {
4
5    // 省略其他代码
6}
2、配置⽂件配置内容为:
(不包括项⽬中的其他配置,这⾥只是数据源相关的)
1# 主数据源,默认的
2spring.datasource.sql.jdbc.Driver
3spring.datasource.url=jdbc:mysql://localhost:3306/test
4spring.datasource.username=root
5spring.datasource.password=123456
6
7# 更多数据源
8custom.datasource.names=ds1,ds2
9custom.datasource.ds1.sql.jdbc.Driver
10custom.datasource.ds1.url=jdbc:mysql://localhost:3306/test1
11custom.datasource.ds1.username=root
12custom.datasource.ds1.password=123456
13
14custom.datasource.ds2.sql.jdbc.Driver
15custom.datasource.ds2.url=jdbc:mysql://localhost:3306/test2
16custom.datasource.ds2.username=root
17custom.datasource.ds2.password=123456
3、使⽤⽅法
1package org.springboot.sample.service;
2
3import java.sql.ResultSet;
4import java.sql.SQLException;
5import java.util.List;
6
7import org.springboot.sample.datasource.TargetDataSource;
8import org.ity.Student;
9import org.springboot.sample.mapper.StudentMapper;
10import org.springframework.beans.factory.annotation.Autowired;
11import org.JdbcTemplate;
12import org.RowMapper;
13import org.springframework.stereotype.Service;
14
15/**
16 * Student Service
17 *
18 * @author  单红宇(365384722)
18 * @author  单红宇(365384722)
19 * @myblog  blog.csdn/catoop/
20 * @create    2016年1⽉12⽇
21 */
22@Service
23public class StudentService {
24
25    @Autowired
26    private JdbcTemplate jdbcTemplate;
27
28    // MyBatis的Mapper⽅法定义接⼝
29    @Autowired
30    private StudentMapper studentMapper;
31
32    @TargetDataSource(name="ds2")
33    public List<Student> likeName(String name){
34        return studentMapper.likeName(name);
35    }
36
37    public List<Student> likeNameByDefaultDataSource(String name){
38        return studentMapper.likeName(name);
39    }
40
41    /**
42    * 不指定数据源使⽤默认数据源
43    *
44    * @return
45    * @author SHANHY
46    * @create  2016年1⽉24⽇
47    */
48    public List<Student> getList(){
49        String sql = "SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE  FROM STUDENT";
50        return (List<Student>) jdbcTemplate.query(sql, new RowMapper<Student>(){
51
52            @Override
53            public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
54                Student stu = new Student();
55                stu.Int("ID"));
56                stu.Int("AGE"));
57                stu.String("NAME"));
58                stu.String("SCORE_SUM"));
59                stu.String("SCORE_AVG"));
60                return stu;
61            }
62
63        });
64    }
65
66    /**
67    * 指定数据源
68    *
69    * @return
70    * @author SHANHY
71    * @create  2016年1⽉24⽇
72    */
73    @TargetDataSource(name="ds1")
74    public List<Student> getListByDs1(){
75        String sql = "SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE  FROM STUDENT";
76        return (List<Student>) jdbcTemplate.query(sql, new RowMapper<Student>(){
77
78            @Override
79            public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
80                Student stu = new Student();
81                stu.Int("ID"));
82                stu.Int("AGE"));
83                stu.String("NAME"));
84                stu.String("SCORE_SUM"));
85                stu.String("SCORE_AVG"));
86                return stu;
87            }
88
89        });
90    }
91
92    /**
93    * 指定数据源
94    *
95    * @return
96    * @author SHANHY
97    * @create  2016年1⽉24⽇
98    */
99    @TargetDataSource(name="ds2")
100    public List<Student> getListByDs2(){
101        String sql = "SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE  FROM STUDENT";
102        return (List<Student>) jdbcTemplate.query(sql, new RowMapper<Student>(){
103
104            @Override
105            public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
106                Student stu = new Student();
107                stu.Int("ID"));
108                stu.Int("AGE"));
109                stu.String("NAME"));
110                stu.String("SCORE_SUM"));
111                stu.String("SCORE_AVG"));
112                return stu;
113            }
114
115        });
116    }
117}
要注意的是,在使⽤MyBatis时,注解@TargetDataSource 不能直接在接⼝类Mapper上使⽤。 按上⾯的代码中StudentMapper为接⼝,代码如下:
1package org.springboot.sample.mapper;
2
3import java.util.List;
4
5import org.ity.Student;
6
7/**
8 * StudentMapper,映射SQL语句的接⼝,⽆逻辑实现
9 *
10 * @author 单红宇(365384722)
11 * @myblog blog.csdn/catoop/
12 * @create 2016年1⽉20⽇
13 */
14public interface StudentMapper {
15
16    // 注解 @TargetDataSource 不可以在这⾥使⽤
17    List<Student> likeName(String name);
18
19    Student getById(int id);
20
21    String getNameById(int id);
22
23}
请将下⾯⼏个类放到Spring Boot项⽬中。
DynamicDataSource.java
DynamicDataSourceAspect.java
DynamicDataSourceContextHolder.java
DynamicDataSourceRegister.java
TargetDataSource.java
1package org.springboot.sample.datasource;
2
3import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
4
5/**
6 * 动态数据源
7 *
8 * @author  单红宇(365384722)
9 * @myblog  blog.csdn/catoop/
10 * @create    2016年1⽉22⽇
11 */springboot aop
12public class DynamicDataSource extends AbstractRoutingDataSource {
13
14    @Override
15    protected Object determineCurrentLookupKey() {
16        DataSourceType();
17    }
18
19}
1package org.springboot.sample.datasource;
2
3import org.aspectj.lang.JoinPoint;
4import org.aspectj.lang.annotation.After;
5import org.aspectj.lang.annotation.Aspect;
6import org.aspectj.lang.annotation.Before;
7import org.slf4j.Logger;
8import org.slf4j.LoggerFactory;
9import org.springframework.stereotype.Component;
10
11/**
12 * 切换数据源Advice
13 *
14 * @author 单红宇(365384722)
15 * @myblog blog.csdn/catoop/
16 * @create 2016年1⽉23⽇
17 */
18@Aspect
19@Order(-1)// 保证该AOP在@Transactional之前执⾏
20@Component
21public class DynamicDataSourceAspect {
22
23    private static final Logger logger = Logger(DynamicDataSourceAspect.class); 24
25    @Before("@annotation(ds)")
26    public void changeDataSource(JoinPoint point, TargetDataSource ds) throws Throwable {
27        String dsId = ds.name();
28        if (!ainsDataSource(dsId)) {
29            ("数据源[{}]不存在,使⽤默认数据源 > {}", ds.name(), Signature());
30        } else {
31            logger.debug("Use DataSource : {} > {}", ds.name(), Signature());
32            DynamicDataSourceContextHolder.setDataSourceType(ds.name());
33        }
34    }
35
36    @After("@annotation(ds)")
37    public void restoreDataSource(JoinPoint point, TargetDataSource ds) {
38        logger.debug("Revert DataSource : {} > {}", ds.name(), Signature());
39        DynamicDataSourceContextHolder.clearDataSourceType();
40    }
41
42}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。