一、多数据源使用场景
从业务角度来看:
- 业务复杂(数据量大)-分库分表
数据分布在不同的数据库中,数据库拆了,应用没拆。一个公司多个子项目,各用各的数据库,涉及数据共享(这种情况也可以使用OpenFeign进行服务间调用,但是存在http调用网络损耗)
分库分表,根据业务来划分不同的库,比如与用户相关的表在db_user库,与订单相关的表在db_order库。
- 读写分离
master和slave模式,master库只用来写入数据,slave库只用来读取数据。
为了解决数据库的读性能瓶颈(读比写性能更高,写锁会影响读阻塞,从而影响读的性能)。很多数据库拥有主从架构。也就是,一台主数据库服务器,是对外提供增删改业务的生产服务器;另一(多)台从数据库服务器,主要进行读的操作。
可以通过中间件(ShardingSphere、mycat、mysql-proxy、TDDL......),但是有一些规模较小的公司,没有专门的中间件团队搭建读写分离基础设施,因此需要业务开发人员自行实现读写分离。
从技术角度来看:
- 数据库高性能场景:主从,包括一主一从、一主多从等。在主库进行增删改操作,在从库进行读操作。
- 数据库高可用场景:主备,包括一主一备、多主多备等。在数据库无法访问时可以切换。
- 同构或异构数据的业务处理:需要处理的数据存储在不同的数据库中,包括同构(如都是MySQL)、异构(如一个MySQL,另外是PG或者Oracle)。
实际项目开发中遇到的情况:
- basic服务,既要连接菜单库、又要连接用户库
- 风控系统、连接不同的业务库对业务进行事前、事中、事后校验(业务前校验、保存校验、提交校验、发钱之后重新校验)
- 在征得客户同意、并且是总集或者也是自己的服务数据库的情况下(比如就业调用社保)。为什么不用接口进行数据传输?提供的接口一般都是查单个人或者单个公司的,就业业务动不动就要批量查,这种情况下循环调用的话,网络传输的损耗比较大,直查数据库速度快很多。但是这种一般不直接连对方的生产库,一般都是连对方的备份库,避免查询量较大把对方生产库直接宕机。
- 新老数据库同步。(经办系统上新,但是友商老系统数据库仍然实时为大数据中心提供服务,需要实时写入。如果不用实时写入的话,完全可以使用数据库定时同步)
二、实现方式
一般来说,使用aop进行事务拦截,开启事务时,对数据源key进行判断选择用哪个数据源。
这里直接使用MyBatis Plus提供的@DS注解进行实现。
注:一般来说,都是用ThreadLocal来存储当前线程的数据库key变量的。
三、多数据源使用过程中的事务问题
在动态切换数据库当中,遇到了@Transational和@DS冲突的问题。
1.场景模拟
1.1 先导入pom.xml依赖
xml
代码解读
复制代码
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 数据源切换依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.5.2</version> </dependency> <!-- MySQL依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.29</version> </dependency> <!-- Mybatis依赖 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version>