前言
之前一直没用过多数据源的方式,这次由于新领导要求,尽量少的使用fegin调用。推荐我们使用多数据源的方式。在目前的开发过程中遇到了些问题,我就顺带将配置方式和遇到的问题一起列出来。
场景
在实际开发中,经常会遇到页面的展示数据来源于多个数据库的组合数据。为什么会发生这种情况呢?现在的主流思想就是,功能隔离,然后就因为功能拆分导致数据库也会拆分,但是部分数据又是共享的,所以要么多数据源,要么各服务之间进行调用,其实也可以去适用视图。根据功能需求,以及领导的意见吧。
代码
一、依赖
<!--多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
二、application.yml配置文件
spring:
datasource:
dynamic:
primary: master #这是默认数据源,必须设置
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
hikari: # 全局hikariCP参数,所有值和默认保持一致。(现已支持的参数如下,不清楚含义不要乱设置)
minimum-idle: 5
maximum-pool-size: 15
connection-timeout: 30000
auto-commit: true
idle-timeout: 30000
max-lifetime: 1800000
connection-test-query: SELECT 1
datasource:
master:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true
username: root
password: root
db2:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/db2?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true
username: root
password: giga@163.com
db3:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/db3?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true
username: root
password: giga@163.com
问题一:
其中primary: master,这个是必须的,必须要设置默认数据源或者主数据源,否则会报错。
我遇到过这么一个问题:我设置primary: master,但是在启动的时候一直提示我没有设置默认数据源。烦恼了好久,然后我把后面的备注:#这是默认数据源,必须设置。这段删掉后,就没有问题了。不知道是不是因为nacos的版本问题,如果有遇到这种情况可以试着删掉试试看。
三、代码
如果使用的是默认数据源,那就和平时的写法是一样的,该怎么处理怎么处理。我这边就不多做叙述了。如果用的是除了默认数据源以外的其他数据源的话。可以看一下下发的代码,在WasteServiceImpl的类上加上@DS("db2")或者是方法上加上@DS("db2"),其中的db2并不是数据库的名字,而是你配置文件中给他起的名字,这样就会使用该数据源了。
@DS("db2")
@Service
public class WasteServiceImpl implements WasteService {
private final WasteMapper wasteMapper;
public WasteServiceImpl(WasteMapper wasteMapper) {
this.wasteMapper = wasteMapper;
}
@DS("db3")
@Override
public List<AlarmWasteLogVo> getAlarmWasteLogList(String startDate, String endDate) {
List<AlarmWasteLog> alarmWasteLogList= wasteMapper.getAlarmWasteLogListByTime(startDate,endDate);
if(CollectionUtils.isEmpty(alarmWasteLogList)){
return null;
}
List<AlarmWasteLogVo> alarmWasteLogVos = Convert.toList(AlarmWasteLogVo.class, alarmWasteLogList);
return alarmWasteLogVos;
}
}
上图所示,当有两个@DS的时候,是谁靠的近,就是谁。那么这图中适用的数据源就是db3。
问题二:
在我们实际开发中经常会使用到事务,当我们在某一个事务里去需要调另一个数据源的查询的时候,你会发现查询会报错说,找不到该表。这是因为在同一个事务里没有办法去切换数据源,我们需要去新开一个事务,如下图所示,这样就可以了:
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public String getOrgIdBySysUserId(String sysUserId) {
return lambdaQuery().select(PersonInfo::getOrgId).eq(PersonInfo::getSysUserId, sysUserId).one().getOrgId();
}
这也就导致了同一个事务下的同一方法下,用mybatis的lambda查询时就没办法使用了。因为没有新开事务切换不了数据源。只能重新写个方法进行调用咯。没办法偷懒了。
总结
确实在部分场景使用多数据源会比较方便,但同时部分代码也确实是重复开发了。目前遇到的情况不多,后续不知道还有没有其他问题,就先这样吧!