Dynamic-Datasource
dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。
其支持 Jdk 1.7+, SpringBoot 1.5.x 和 2.x.x。
作用:实现读写分离
特性
- 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
- 支持数据库敏感配置信息 加密 ENC()。
- 支持每个数据库独立初始化表结构schema和数据库database。
- 支持 自定义注解 ,需继承DS(3.2.0+)。
- 提供对Druid,Mybatis-Plus,P6sy,Jndi的快速集成。
- 简化Druid和HikariCp配置,提供 全局参数配置 。配置一次,全局通用。
- 提供 自定义数据源来源 方案。
- 提供项目启动后 动态增加移除数据源 方案。
- 提供Mybatis环境下的 纯读写分离 方案。
- 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。
- 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
- 提供对shiro,sharding-jdbc,quartz等第三方库集成的方案,注意事项和示例。
- 提供 基于seata的分布式事务方案。 附:不支持原生spring事务。
约定
- 本框架只做 切换数据源 这件核心的事情。
- 配置文件所有以下划线
_
分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。 - 切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。
- 默认的数据源名称为 master ,你可以通过
spring.datasource.dynamic.primary
修改。 -
@DS
注解可以注解在类或方法上。方法上的注解优先于类上注解。
快速入门
-
创建一个springboot工程,导入mysql、druid和Dynamic-Datasource的启动器。
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--导入druid的启动器--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.18</version> </dependency> <!--导入dynamic-datasource的启动器--> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies>
-
配置文件,配置
主库
和从库
。需要最少两个mysql服务。spring: datasource: dynamic: primary: master #设置默认的数据源或者数据源组,默认值即为master strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源. datasource: master: #配置主库 url: jdbc:mysql://8.131.88.207:3306/test?serverTimezone=Asia/Shanghai username: 用户名 password: 密码 driver-class-name: com.mysql.cj.jdbc.Driver slave_1: #配置从库 url: jdbc:mysql:///test01?serverTimezone=Asia/Shanghai username: 用户名 password: 密码 driver-class-name: com.mysql.cj.jdbc.Driver
-
在启动类@SpringBootApplication注解中,排除原生Druid的配置类。因为项目默认连接Druid的原生配置的mysql服务。
@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class) public class BaomidouDynamicDatasourceApplication { public static void main(String[] args) { SpringApplication.run(BaomidouDynamicDatasourceApplication.class, args); } }
-
我的主库或从库都有一个同一结构的表:student表,只有
id
和name
两个属性。编写对应的实体类Student.class。public class Student { private int id; private String name; //省略get/set/constructor/toString方法 }
-
编写dao层、service层与controller层。
dao层中,如果想要从主库查询,默认不需要添加注解;如果想从从库中查询,则添加注解@DS("slave_1")
,slave_1
是在配置中定义的从库名称。例如我,查询从从库,读写在主库。
dao实现:
@Repository public class StudentDaoImpl implements StudentDao { @Autowired private JdbcTemplate jdbcTemplate; @Override @DS("slave_1") //表示读取数据源为从库,若没有注解则默认为主库 public List<Student> allStudent() { return jdbcTemplate.query("select * from student ", new RowMapper<Student>() { @Override public Student mapRow(ResultSet resultSet, int i) throws SQLException { Student student=new Student(Integer.parseInt(resultSet.getString("id")),resultSet.getString("name")); return student; } }); } @Override public void addStudent(String name) { jdbcTemplate.execute("INSERT INTO student(NAME) VALUES(' "+name+" '); "); } }
service实现:
@Service public class StudentServiceImpl implements StudentService { @Autowired private StudentDao studentDao; @Override public List<Student> allStudent() { return studentDao.allStudent(); } @Override public void addStudent(String name) { studentDao.addStudent(name); } }
controller层:
@RestController public class Test { @Autowired private StudentService studentService; @GetMapping("allStudent") public String allStudent(){ return studentService.allStudent().toString(); } @GetMapping("addStudent") public String addStudent(){ studentService.addStudent("思绪"); return "添加成功"; } }
-
测试:我的两个mysql服务并没有主从复制,所以数据并不同步。
-
添加数据:默认在主库中添加。
-
查找数据:从从库查找。
-
集成MybatisPlus
-
首先导入Mybatis的依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> </dependency>
-
在启动类配置
@MapperScan
扫描Mapper层@MapperScan("com.sixu.dao")
-
编写一个mapper层,StudentMapper.class,继承BaseMapper <Studen> , 就可以直接使用MybatisPlus内置的mapper层方法了。
public interface StudentMapper extends BaseMapper<Student> { }
-
在service层调用这个mapper的方法,并且在在方法上添加
@DS
验证效果。//读取从库 @DS("slave_1") public List<Student> slave(){ return studentMapper.selectList(null); } //读取主库 public List<Student> master(){ return studentMapper.selectList(null); }
-
controller层
//整合mybatisplus,实现读写分离,读取从库 @GetMapping("slave") public String slave(){ return studentService.test().toString(); } //整合mybatisplus,实现读写分离,读取主库 @GetMapping("master") public String master(){ return studentService.test().toString(); }
-
测试结果: