springboot+mybatis-plus多数据源切换saveBatch时失效

背景

最近同事在使用mybatis-plus的saveBatch方法时发现报错,提示连接被拒绝,而换成save方法可以正常执行。

环境介绍

多数据源master-slave,只从slave读取数据,动态数据源切换是通过sping提供的AbstractRoutingDataSource实现,通过实现mybatis插件,在执行sql时通过sql语句来进行主从库数据源的指定。

springboot 2.3.6.RELEASE

mybatis-plus 3.4.2

mybatis 3.5.6

druid 1.1.21

mysql 8.0.22

问题分析与解决

  1. 根据报错信息,提示操作被拒绝,使用的是slave库的connection去执行插入操作
  2. 代码逻辑里只有读数据才会连接slave库,也就是selectt语句才会连接slave库操作,这块不会有错,代码上线已久,不会是主从库路由的问题
  3. 同时发现save操作是正常的,说明问题出在了saveBatch方法上
  4. 通过断点发现,saveBatch没有执行到mybatis数据源路由的插件逻辑里,而save是可以正常执行路由插件的逻辑的
  5. 解决方法是,手动在mapper xml里写批量插入的方法

源码阅读

查看saveBatch方法源码com.baomidou.mybatisplus.extension.service.IService#saveBatch(java.util.Collection)


通过传递一个函数参数到下一层执行,这里的insert继续往下走发现com.baomidou.mybatisplus.core.executor.MybatisBatchExecutor#doUpdate用于拼接sql与获取connection


进入getConnection方法



org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection


org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#getConnection()

至此,saveBatch就从determineTargetDataSource中获取到了slave的connection,这里为什么会是slave的connection呢?原来是在批量插入操作之前有一个查询的select操作,导致存放数据源路由的threadLocal中保存的是slave标记。在这里获取完connection后,代码走到数据源路由拦截器中指定master数据源,正确指定master后不生效,这里应该是mybatis-plus的一个bug了。

这样,我们还可以通过在saveBatch执行前,强制将数据源指定为MASTER也可以解决这个问题。

展开阅读全文

页面更新:2024-05-29

标签:主从   数据源   路由   批量   插件   逻辑   代码   操作   发现   方法

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top