R2dbc Mybatis 整合
涉及到框架
r2dbc-spi
r2dbc-pool
reactor-core
mybatis
mybatis-dynamic-sql
spring-r2dbc
背景原因
- 在介入Reactive技术栈时,将原有的
mybatis
框架 reactive 化的过程中,整合Transaction遇到的技术难点 - 考察过社区很多 reactive 应用框架,除了
Spring-R2DBC
外,大部分事物处理,和connection管理,都还停留在阻塞式处理的思路中。并没有真正的实现reactive化
技术难点
- 1 . 由于Reactive的编程模式相对于传统编程模式的变化,
ThreadLocal
已无法在reactive环境中使用,造成connection无法缓存,导致在业务流程上挂载事务处理时,无法缓存connection - 2 . 虽然r2dbc的connection提供了transaction操作,但要将
mybatis
框架 reactive 化的过程中,通过Context
合理的缓存Connection
不太好实现
背景知识
- 用于创建statement,操作事物等
- 创建connection
Reactive-Mybatis
在整合
r2dbc
和mybatis
时,有一系列问题需要适配:- reactive项目中无法使用ThreadLocal,需要替换为
Context
,用于缓存Connection
- reactive,属于数据流处理的形式,原有Mybatis中的处理逻辑是Blocking操作,需要替换为No-Blocking
- 保留原有参数绑定和结果解析方案,并适配到reactive流处理过程中
r2dbc-spi
驱动中,PreparedStatement中的占位符,不同驱动有不同的实现,而JDBC
统一使用?
为占位符,由驱动翻译占位符,这里需要转换为框架适配,否则适配不同的r2dbc
驱动- 由于reactive本身就有cache性质,需要将
mybatis
中的cache剥离掉 - 适配
r2dbc
Data-Type,否则数据映射不成功
- reactive项目中无法使用ThreadLocal,需要替换为
- 在整合
r2dbc
事物时,需要使用动态代理来实现缓存Connection
到Context
中,并保证,在一个事物中,Connection
是同一个,这样才能实现Transaction
- 在解析返回结果集时,需要切换思路,由于数据是按照数据流的形式返回的,那么在合并和解析结果集时,需要合理缓存已解析的数据,从而可以保留原有
mybatis
的一对多映射功能 - 在适配
SelectKey
功能时,需要将原有的before
和after
操作,转移到executor中操作,原有的SelectKey
功能是阻塞的,需要将流程贯穿到整个executor
过程中,才能保留before
和after
操作 - 由于
r2dbc
的限制,要么只返回自生成自增主键
,要么返回影响行数
Reactive-Mybatis-Spring
- 整合到Spring的过程中,需要将Executor挂在到Spring的事物管理器上,并交由Spring管理
- Spring通过
ConnectionFactoryUtils.currentConnectionFactory(connectionFactory)
来判断,当前Context是否有事物管理 - Spring提供了
TransactionAwareConnectionFactoryProxy
来代理事物,需要将ReactiveSqlSession
中使用的ConnectionFactory
替换为TransactionAwareConnectionFactoryProxy
才能和Spring的事物管理器一起使用
相关信息
- 已通过Mybatis源码,适配了R2DBC,保留Mybatis原用功能,尽可能的保证项目顺利迁移。具体支持的功能,请移步 reactive-mybatis-support
- 已发布到中央仓库,测试了
MySQL
/PostgreSQL
/H2
/Mssql
/Oracle
相关源码维护在GitHub,欢迎Issue和Star reactive-mybatis-support
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。