目录
起源
最近公司要做多租户,mybatis-plus的多租户插件很好用,但是有一个场景是:字典表或者某些数据表,一些数据需要在各个租户之间共享,而数据表本身又同时要实现多租户数据隔离,比如字典表:性别等“男”/“女”基础数据。
sql拦截器是一种用于拦截和修改mybatis执行的sql语句的工具。通过使用sql拦截器,开发人员可以在执行sql语句之前或之后对其进行修改或记录,从而更好地控制和优化数据库操作。例如mybatis-plus的基础分页插件、多租户插件就是sql拦截器,那么,我们是否可以实现自己的sql拦截器呢?
答案当然是肯定的。
实现拦截器接口innerinterceptor
innerinterceptor 这个接口是mybaitsplus的拦截器接口类,实现它之后,并且通过mybatisplusinterceptor配置后,就可以实现sql执行拦截。
mybatisplusinterceptor interceptor = new mybatisplusinterceptor(); // 多租户拦截器 interceptor.addinnerinterceptor(new tenantlineinnerinterceptor(new tenantdatabaseinterceptor(tenantproperties))); // 多租户部分表数据共享拦截器 interceptor.addinnerinterceptor(new tenantdatabaseshareinterceptor(new tenantsharehandlerimpl(tenantproperties)));
那么如何实现该接口以及修改sql呢?
下面是一个样例:
import com.baomidou.mybatisplus.core.interceptor.innerinterceptor; import com.baomidou.mybatisplus.core.metadata.ipage; import com.baomidou.mybatisplus.core.parser.sqlparserhelper; import com.baomidou.mybatisplus.extension.plugins.inner.innerinterceptorchain; import net.sf.jsqlparser.parser.ccjsqlparserutil; import net.sf.jsqlparser.statement.statement; import net.sf.jsqlparser.statement.select.select; public class myinterceptor implements innerinterceptor { @override ``` @override public void beforequery(executor executor, mappedstatement ms, object parameter, rowbounds rowbounds, resulthandler resulthandler, boundsql boundsql) throws sqlexception { if (interceptorignorehelper.willignoretenantline(ms.getid())) return; pluginutils.mpboundsql mpbs = pluginutils.mpboundsql(boundsql); mpbs.sql(parsersingle(mpbs.sql(), null)); } }
通过修改beforequery函数中的代码,即可修改执行的sql。
修改sql常用的工具类
jsqlparsersupport
该类用于解析与修改sql,并且mybatisplus的多租户插件更是直接继承了该类。 ccjsqlparserutil
是jsqlparser中用于解析sql语句的工具类。它提供了一些静态方法,可以将sql语句解析为statement
对象、select
对象、update
对象、insert
对象、delete
对象等。
常用的类还有expression
, statement
等类。
例如,使用expression实现一个in语句:
import net.sf.jsqlparser.expression.expression; import net.sf.jsqlparser.expression.longvalue; import net.sf.jsqlparser.expression.stringvalue; import net.sf.jsqlparser.expression.operators.relational.inexpression; import net.sf.jsqlparser.expression.operators.relational.itemslist; import net.sf.jsqlparser.expression.operators.relational.multiexpressionlist; import net.sf.jsqlparser.expression.operators.relational.namedparameter; import net.sf.jsqlparser.expression.operators.relational.subselect; import net.sf.jsqlparser.parser.ccjsqlparserutil; public class jsqlparserexample { public static void main(string[] args) throws exception { // in语句 inexpression inexpr = new inexpression(); inexpr.setleftexpression(ccjsqlparserutil.parseexpression("age")); itemslist valuelist = new multiexpressionlist(); ((multiexpressionlist) valuelist).addexpressions(new longvalue(18), new longvalue(21), new longvalue(30)); inexpr.setitemslist(valuelist); system.out.println(inexpr.tostring()); // 子查询 inexpression subqueryinexpr = new inexpression(); subqueryinexpr.setleftexpression(ccjsqlparserutil.parseexpression("age")); subselect subquery = new subselect(); subquery.setselectbody(ccjsqlparserutil.parse("select age from users where country = 'us'")); subqueryinexpr.setrightexpression(subquery); system.out.println(subqueryinexpr.tostring()); } }