配置多数据源dynamic-datasource 开箱即用方案
1.pom中引入依赖
<!--动态数据源组件--><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>4.3.0</version></dependency>
2.yml配置文件配置多数据源
# spring配置
spring: datasource:druid:stat-view-servlet:enabled: trueloginUsername: 111loginPassword: 111dynamic:druid:initial-size: 5min-idle: 5maxActive: 20maxWait: 60000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: truemaxPoolPreparedStatementPerConnectionSize: 20filters: stat,slf4jconnectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000datasource:# 主库数据源master:# driver-class-name: com.mysql.cj.jdbc.Driver# url: jdbc:mysql://10.99.11.22:12222/abc?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8# username: root# password: 111driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://tbyf-cloud-mysql:3306/def?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: rootpassword: 111# 从库数据源assistant:driver-class-name: oracle.jdbc.OracleDriverurl: jdbc:oracle:thin:@168.888.0.66:1333:hisusername: xypassword: s# seata: true # 开启seata代理,开启后默认每个数据源都代理,如果某个不需要代理可单独关闭# swagger配置
swagger:title: 系统模块接口文档license: tlicenseUrl:
- 含义:
-
dynamic
是关键: 这个配置的核心是spring.datasource.dynamic
节点。这表明它使用了 dynamic-datasource-spring-boot-starter 这个第三方库来实现多数据源管理。 - 定义多个数据源: 在
dynamic.datasource
节点下,明确配置了两个数据源:master
: 使用 MySQL 驱动 (com.mysql.cj.jdbc.Driver
) 和 MySQL JDBC URL。assistant
: 使用 Oracle 驱动 (oracle.jdbc.OracleDriver
) 和 Oracle JDBC URL。
- 共享的 Druid 连接池配置:
dynamic.druid
节点下的配置 (initial-size
,min-idle
,maxActive
,validationQuery
等) 是 Druid 连接池的通用配置。这些配置会被master
和assistant
两个数据源继承。每个数据源也可以有自己的特定配置覆盖通用配置(这里没有展示)。 - Druid 监控配置:
spring.datasource.druid.stat-view-servlet
是配置 Druid 监控台的通用访问设置。 - Seata 集成 (可选):
seata: true
表示集成了 Seata 分布式事务解决方案,该库会自动代理数据源以支持分布式事务。 - 结论: 这是一个真正的多数据源配置,使用了
dynamic-datasource
框架来管理一个 MySQL (master
) 和一个 Oracle (assistant
) 数据源,并使用了 Druid 作为连接池。框架负责数据源的创建、维护和在运行时根据注解(如@DS("master")
)进行动态切换。
3.使用 @DS
注解切换
// 使用MySQL数据源
@Service
@Slf4j
@RequiredArgsConstructor
public class WesternMedDisServiceImpl implements WesternMedDisService {private final RemoteApiService apiconvertBaseinfoService;private final SystemMainMapper systemMainMapper;private final CoZdmlMapper coZdmlMapper;// 要在这里使用DS,在mapper中使用会影响aop执行顺序,aop会先默认将spring管理的事务分给主数据源,在切换数据源是由于开启事务会使用主库@Override@DS("assistant")@Transactional(rollbackFor = Exception.class)public AjaxResult treeNodeUpdate(JSONObject jsonObject) {AjaxResult ajaxResult = new AjaxResult();String treeNodeDialogMode = jsonObject.getString("treeNodeDialogMode");if (StrUtil.isBlank(treeNodeDialogMode)) {return AjaxResult.error("节点修改类型为空,请联系管理员!");}if ("add".equals(treeNodeDialogMode)) {ajaxResult = this.addNode(jsonObject);}if ("insert".equals(treeNodeDialogMode)) {ajaxResult = this.insertNode(jsonObject);}if ("update".equals(treeNodeDialogMode)) {ajaxResult = this.updatetNode(jsonObject);}return ajaxResult;}@Overridepublic List<Tree<JSONObject>> getWTree() {List<JSONObject> westernTree = apiconvertBaseinfoService.getListByApi(3727, new JSONObject()).getData();List<Tree<JSONObject>> treeList = new ArrayList<>();JSONObject object;HashMap<String, Object> Map;for (int i=0;i<westernTree.size();i++){object = westernTree.get(i);Map = new HashMap<>();Tree<JSONObject> JSONTree = new Tree<>();JSONTree.setId(object.getString("MLBM"));JSONTree.setLabel(object.getString("FLBM")+object.getString("FLMC"));JSONTree.setParentId(object.getString("FATHER"));Map.put("QSBM",object.getString("QSBM"));Map.put("JSBM",object.getString("JSBM"));Map.put("FLXH",object.getString("FLXH"));JSONTree.setAttributes(Map);treeList.add(JSONTree);};List<Tree<JSONObject>> trees = BuildTree.buildTree(treeList);return trees;}@Overridepublic AjaxResult checkNodeUsed(JSONObject jsonObject) {String catalogCode = jsonObject.getString("MLBM");if (StrUtil.isBlank(catalogCode)) {throw new ServiceException("删除节点目录类别为空");}String oriSql = "select GY_JBFL.MLBM from GY_JBFLKS,GY_JBFL WHERE GY_JBFLKS.FLXH = GY_JBFL.FLXH AND GY_JBFL.MLBM LIKE \'{}\'";String sql = StrUtil.format(oriSql,catalogCode);List<Map<String, Object>> list = systemMainMapper.getMapObject(sql);return AjaxResult.success(list.size());}@Overridepublic AjaxResult deleteNode(JSONObject jsonObject) {int i = systemMainMapper.deleteNode(jsonObject.getString("FLXH"));return AjaxResult.success(i);}public AjaxResult addNode(JSONObject jsonObject) {JSONObject treeNodeForm = jsonObject.getJSONObject("treeNodeForm");JSONObject rightCurrentNodeData = jsonObject.getJSONObject("rightCurrentNodeData");Integer maxNo = jsonObject.getInteger("MAXNO");treeNodeForm.put("FLXH", maxNo);JSONArray children = rightCurrentNodeData.getJSONArray("children");Optional<JSONArray> optionalMap = Optional.ofNullable(children);// 选中添加节点存在子节点if (optionalMap.isPresent()) {Map lastChildren =(Map) children.get(children.size() - 1);String lastChildrenId = (String) lastChildren.get("id");/*** MLBM用来分层,01 02...代表第一层,0101 0102代表第二层,如果需要找到父节点id只需找到当前MLBM再截取最后两位即可* 例如:0101 的父节点是01,01 02的父节点是0*/// 转成Integer会将前导0去除,计算出值以后手动补上最前面的0treeNodeForm.put("MLBM","0" + (Integer.parseInt(lastChildrenId) + 1));} else {String id = rightCurrentNodeData.getString("id");treeNodeForm.put("MLBM","0" + (Integer.parseInt(id + "01")));}int i = systemMainMapper.insertTreeNodeForm(treeNodeForm);return AjaxResult.success(i);}public AjaxResult insertNode(JSONObject jsonObject) {JSONObject treeNodeForm = jsonObject.getJSONObject("treeNodeForm");JSONObject rightCurrentNodeData = jsonObject.getJSONObject("rightCurrentNodeData");Integer maxNo = jsonObject.getInteger("MAXNO");treeNodeForm.put("FLXH", maxNo);String parentId = rightCurrentNodeData.getString("parentId");treeNodeForm.put("MLBM", parentId + "01");// 获取当前插入节点父节点下所有子节点List<Map<String, Object>> nodes = systemMainMapper.getNodesByParentId(parentId);List<Map<String, Object>> list = nodes.stream().map(item -> {String catalogCode = (String) item.get("MLBM");if (catalogCode.startsWith("0")) {catalogCode = "0" + (Integer.parseInt(catalogCode) + 1);} else {catalogCode = StrUtil.toString(Integer.parseInt(catalogCode) + 1);}item.put("MLBM", catalogCode);return item;}).collect(Collectors.toList());systemMainMapper.batchUpdateGyJbfl(list);int insert = systemMainMapper.insertTreeNodeForm(treeNodeForm);return AjaxResult.success(insert);}public AjaxResult updatetNode(JSONObject jsonObject) {JSONObject treeNodeForm = jsonObject.getJSONObject("treeNodeForm");int i = systemMainMapper.updateTreeNodeForm(treeNodeForm);return AjaxResult.success(i);}@Overridepublic List<Tree<JSONObject>> statisticalWTreeBuilder() {List<JSONObject> westernTree = apiconvertBaseinfoService.getListByApi(3945, new JSONObject()).getData();List<Tree<JSONObject>> treeList = new ArrayList<>();JSONObject object;HashMap<String, Object> Map;for (int i=0;i<westernTree.size();i++){Map = new HashMap<>();object = westernTree.get(i);Tree<JSONObject> JSONTree = new Tree<>();JSONTree.setId(object.getString("MLBM"));JSONTree.setLabel(object.getString("TJMC")+ "[" + object.getString("TJBM") + "]");JSONTree.setParentId(object.getString("FATHER"));Map.put("FLXH",object.getString("TJXH"));Map.put("GLICD",object.getString("GLICD"));JSONTree.setAttributes(Map);treeList.add(JSONTree);};List<Tree<JSONObject>> trees = BuildTree.buildTree(treeList);return trees;}@Overridepublic AjaxResult cbSave(List<CoZdml> coZdmls) {CoZdml coZdml = coZdmls.get(0);if (coZdmls.size() == 1) {String ls_dm = coZdml.getDm();String ls_dmmc = coZdml.getDmmc();Long ll_zfbz = coZdml.getZfbz();if (StrUtil.isBlank(ls_dm)) {return AjaxResult.error("ICD码不能为空!");}if (StrUtil.isBlank(ls_dmmc)) {return AjaxResult.error("疾病名称不能为空!");}}Integer integer = coZdmlMapper.addOrUpdateCoZdml(coZdmls);return AjaxResult.success(integer);}@Overridepublic AjaxResult cbDelete(CoZdml coZdmls) {int delete = coZdmlMapper.deleteById(coZdmls.getDm());return AjaxResult.success(delete);}
}
@Mapper
public interface SystemMainMapper {@DS("assistant")List<Map<String,Object>> getMapObject(@Param("sql") String sql);@DS("assistant")IPage<JSONObject> getMapObjectPage(Page page, @Param("sql") String sql);ApiconvertBaseinfo selectApiconvertBaseinfoByApiId(@Param("apiId") Long apiId);int insertTreeNodeForm(@Param("treeNodeForm") Map<String, Object> treeNodeForm);int updateTreeNodeForm(@Param("treeNodeForm") Map<String, Object> treeNodeForm);List<Map<String,Object>> getNodesByParentId(@Param("parentId") String parentId);int batchUpdateGyJbfl(@Param("list") List<Map<String, Object>> list);int deleteNode(@Param("FLXH") String id);
}