在前一章中,我们介绍完了数据库读写分离所需要的基础环境的的搭建。详见:【基于SpringBoot的MYSQL数据库读写分离(一)——基础环境搭建】在本章中,将介绍如何使用Springboot去实现动态切换数据源。
Springboot项目的构建
首先,我们在idea中创建一个新项目。在pom中引入如下的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
然后在application.yml中,配置各个数据库的参数
实现代码的编写
由于使用了mysql5以上的版本,所以在这里使用的driverClassName是com.mysql.cj.jdbc.Driver
,假如使用的是mysql5及以下版本,则应使用com.mysql.jdbc.Driver
。
新建建一个叫config的包,我们所需要的配置,在这个包里面完成。
新建一个枚举类型,枚举值我们定义为MASTER, SLAVE1, SLAVE2
![](https://img-blog.csdnimg.cn/20190709204115614.png)
再新建一个名叫DBContextHolder的类,这个类我们用于动态切换数据源。主要的的内容,我在代码中使用了注释解释了一下。
然后新建一个叫RoutingDataSource的类,这个类需要继承AbstractRoutingDataSource这个抽象类,在AbstractRoutingDataSource这个抽象类中,有一个叫targetDataSources的map,这里面可以存放我们的多个数据源。我们重写determineCurrentLookupKey方法,使用之前的DBContextHolder去获取目前需要使用的是哪个库。
新建一个名叫DataSourceConfig的类,在这个类中,我们初始化三个数据库的DataSource,然后再将这三个DataSource加载到targetDataSources中。
再创建SqlSessionFactoryConfig类,去初始化sqlSessionFactory,将刚才加载的数据源targetDataSource自动注入进来,然后指定好mapper的路径,这样,我们的数据库加载就初始化完成了。
mapper文件,可以通过Mybatis的Generator逆向工程自动生成,也可以自己手动编写,我这里就通过逆向工程生成了一下,并将mapper放置到指定的目录中去。
![](https://img-blog.csdnimg.cn/20190710113022806.png)
接下来编写service类,在service中简单实现对数据库的增删改查四个接口。接口和实现类如下图所示。
最后我们在service层,实现数据源的动态切换,编写面向切面的AOP类,将切点设置在service层的每一个方法上,方法名前缀大致为:
- 读库:select*、get*等
- 写库:insert*、add*、update*、edit*、delete*、remove*等
这里的名称你可以自由定义,只要这里的前缀和service中方法的前缀一致,主库操作查、从库操作增删改即可。
至此,项目的基础搭建已基本完成。
项目测试
我们在测试类中,编写增删改查的四个方法。
首先我们尝试向数据库中插入一个用户,测试结果如下,显示切换到master
我们再查看三个数据库,里面都存在了这条记录,则表明我们的记录插入成功了,而后我们再多插入两条测试记录。
而后,我们执行查询操作,查询了三条记录,可以看到,加载了两个从库的数据源,同时实现了负载均衡的切换数据源。
然后我们测试修改,将id为3的用户修改其个人信息,控制台也输出了切换到Master。
查看数据库,发现各个库中id为3的用户信息都已被修改。
最后,我们测试删除功能,将ID为1的用户删除,控制台输出切换到Master。
三个数据库中都显示id为1的用户被删除了。
至此,功能性测试完成。我们可以看到,执行增删改的所有操作都使用了主库执行,而查询则是通过轮询的方式,在两个从库之间来回切换。这样,最简易的数据库读写分离就基本完成了。