如何在orm框架如mybatis的基础上实现自己的sql拦截需求(分表等)

场景

针对一些业务中通用的sql拦截需求,比如数据库分表,让sql自动带上分表号,对业务完全透明,是最好的做法,这就涉及到拦截,这层拦截在应用这层做可以减小数据库的压力,并且减小对数据库的依赖,利于伸缩。所谓拦截,就是在方法的统一入口处进行控制,以下针对java中的一种orm框架mybatis进行具体描述。

实现原理

mybatis提供了interceptors机制,在其重要组件比如参数组装器、结果集组装器、statement组装器和sql执行器 executor上都提供了interceptor支持。我们的分表需求就可以在executor这一层做拦截,生成新的sql语句以及参数列表。

具体实现以及测试代码见:https://github.com/guzhangyu/midwares/tree/master/unitymob-batch

思路所需储备

1. 首先,简单介绍一下mybatis的组件以及sql执行过程

耳熟能详的SqlSession是通过executor执行的sql的:
这里写图片描述

顺藤摸瓜,executor和session是什么时候初始化的?
这里写图片描述

2. 接下来分析interceptor是怎么实现

普通的拦截器需要自己去控制拦截的方法,获取拦截的参数、执行相应的工作;mybatis这里有多个级别的拦截器,既要实现固定形式的拦截器编写(不用自己写太多拦截器签名等依赖于具体实现的代码),又要通用。mybatis的做法是:首先代理使用的java动态代理,其次定义了注解,用来标识所要拦截的方法。
这里写图片描述

思路来源

那么这个方案是怎么来的呢?需求是mybatis自动生成的mapper实现需要支持batch更新。
一开始准备在mybatis的代码中间注入自己的一些逻辑,在executor执行之前加逻辑,但是mybatis支持的BatchExecutor,由于SqlSession被spring做了一层包装,每次执行sql都自动提交,起不到batch的效果;并且batchExecutor每次update后都返回一个负数的影响行数,这让我十分疑惑mybatis这个BatchExecutor的初始意图何在?

带着疑问,我看了BatchExecutor的实现,里面仅仅对statement做了一次addBatch,没有提交;这说明了它的意图是提供外部多次addBatch,再一次性flush之用,更新条数也就在flush的时候才能拿到。

然后就思索如何能够在中间换executor(从ReuseExecutor到BatchExecutor),将一次executor执行改为多次executor执行,然后一次性flush;然后就去寻找executor生成的地方,这个时候发现executor是每次开启事务的时候初始化的,并且还有一个transaction参数,直观感受在最开始的时候会生成executor(openSession方法中)。

接着看executor初始化的代码,看到plugin这个东西,直觉这个东西帮助很大,跟进去看。发现解决方案的关键;联想到mybatis的分页插件,一看它的实现方式,通过自己的尝试就得到了可行的拦截方案。

更加通用的干货

碰到问题,在解决不了的时候,可以看看它的原理,了解它的流程,在这个过程中梳理思路。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值