本项目使用SpringBoot和MyBatis实现多数据源,动态数据源的切换;有多种不同的实现方式,在学习的过程中发现没有文章将这些方式和常见的问题集中处理,所以将常用的方式和常见的问题都写在了在本项目的不同分支上:
master:使用了多数据源的RESTfulAPI接口,使用Druid实现了DAO层数据源动态切换和只读数据源负载均衡dev:最简单的切面和注解方式实现的动态数据源切换druid:通过切面和注解方式实现的使用Druid连接池的动态数据源切换aspect_dao:通过切面实现的DAO层的动态数据源切换roundrobin:通过切面使用轮询方式实现的只读数据源负载均衡以上分支都是基于dev分支修改或扩充而来,基本涵盖了常用的多数据源动态切换的方式,基本的原理都一样,都是通过切面根据不同的条件在执行数据库操作前切换数据源
在使用的过程中基本踩遍了所有动态数据源切换的坑,将常见的一些坑和解决方法写在了Issues里面
该项目使用了一个可写数据源和多个只读数据源,为了减少数据库压力,使用轮循的方式选择只读数据源;考虑到在一个Service中同时会有读和写的操作,所以本应用使用AOP切面通过DAO层的方法名切换只读数据源;但这种方式要求数据源主从一致,并且应当避免在同一个Service方法中写入后立即查询,如果必须在执行写入操作后立即读取,应当在Service方法上添加
Transactional注解以保证使用主数据源需要注意的是,使用DAO层切面后不应该在Service类层面上加
Transactional注解,而应该添加在方法上,这也是Spring推荐的做法动态切换数据源依赖configuration包下的4个类来实现,分别是:DataSourceRoutingDataSource.javaDataSourceConfigurer.javaDynamicDataSourceContextHolder.javaDynamicDataSourceAspect.java
添加依赖
.
创建数据库及表
分别创建数据库product_master,product_slave_alpha,product_slave_beta,product_slave_gamma在以上数据库中分别创建表product,并插入不同数据
.
.
配置数据源
application.properties
.
.
.
配置数据源
DataSourceKey.java
.
DataSourceRoutingDataSource.java该类继承自AbstractRoutingDataSource类,在访问数据库时会调用该类的determineCurrentLookupKey()方法获取数据库实例的key
.
DataSourceConfigurer.java数据源配置类,在该类中生成多个数据源实例并将其注入到ApplicationContext中
.
.
.
.
DynamicDataSourceContextHolder.java该类为数据源上下文配置,用于切换数据源
.
.
.
.
DynamicDataSourceAspect.java动态数据源切换的切面,切DAO层,通过DAO层方法名判断使用哪个数据源,实现数据源切换关于切面的Order可以可以不设,因为
Transactional是最低的,取决于其他切面的设置,并且在org.springframework.core.annotation.AnnotationAwareOrderComparator会重新排序.
.
配置ProductRESTAPI接口
ProductController.java
.
.
ProductService.java
.
.
ProductDao.java
.
ProductMapper.xml启动项目,此时访问/product/1会返回product_master数据库中product表中的所有数据,多次访问/product会分别返回product_slave_alpha、product_slave_beta、product_slave_gamma数据库中product表中的数据,同时也可以在看到切换数据源的log,说明动态切换数据源是有效的
注意
在该应用中因为使用了DAO层的切面切换数据源,所以
Transactional注解不能加在类上,只能用于方法;有Trasactional注解的方法无法切换数据源.