mybatis数据层的多租户拦截

2019-09-05 22:59发布


互联网厂商在进行公有云saas服务部署的时候,往往会面对多租户的场 景,多租户场景的设计,在架构上一般分为二个层次:

1、计算集群的多租户

计算集群的多租户顾名思义,就是针对不同的租户提供单独的服务集群,不同租户之间cpu相互独立,个别租户的流量洪峰不会影响其它租户正常服务。

计算集群的多租户实现有很多种方案,一般做法是,根据不同租户辟出独立集群,对外暴露统一的CDN域名或BGP域名,经流量调度到计算中心内部,由Nginx集群或网关根据URL中的租户参数,向租户所在集群转发请求。

由于多租户的场景的普遍性,最近几年新涌现的新框架和平台在设计伊始就考虑了多租户的场景,并集成了相关技术,比如k8的namespace,结合calico,可以实现非常灵活的多租户计算分组。

2、数据层的多租户

拿Mysql来举例,数据层的多租户一般有三种做法:

1)一个租户一个数据库

2)一个租户一个schema

3)多个租户同一个schema

其中区别,可以查询相关资料,网上很多,一般Saas服务从成本等因素考虑,大多数采用第3种方案,其主要标志为在元数据设计中,有多租户字段tenant_id。

3、多租户的数据层访问拦截

这里以java+mybatis来说明。

Mybatis plugin插件支持拦截所有提交到Dao层的SQL,并支持对提交的SQL进行改写,原理类似于Spring的Interceptor,多租户Mybatis插件能够在运行时,动态获取到应用上下文中的租户变量,在执行CRUD操作时,自动将多租户字段(tenant_id)条件附加到sql语句之中,如where条件之后。

1)使用mybatis插件的优点

使用mybatis插件,可以大大简化业务代码在多租户改造过程中的开发成本,对比硬编码方式,mapper和dao层无须改造,service层的代码改造量也可以大大降低。

2)原理

通过mybatis plugin拦截sql处理步骤和result处理步骤。sql预处理,自动增加tenant_id相关语句,result预处理,验证数据tenant_id字段符合要求。包括:

  • insert into,增加写入tenant_id数据
  • select 自动在where之后附加条件tenant_id = ?
  • update 在where之后附加条件tenant_id
  • delete 在where之后附加条件tenant_id
  • left join
  • 子查询

等等。

3)实现方式

插件用的是责任链模式,由每一个对象对其下家的引用而连接起来形成一条链,请求在这个链上传递,直到链上的某一个对象决定处理此请求。

具体实现方式为,实现接口Interceptor.java 的3个方法,分别是plugin、intercept和setProperties。




  • intercept:它将直接覆盖你所拦截的对象,有个参数Invocation对象,通过该对象,可以反射调度原来对象的方法;
  • plugin:target是被拦截的对象,它的作用是给被拦截对象生成一个代理对象;
  • setProperties:允许在plugin元素中配置所需参数,该方法在插件初始化的时候会被调用一次

实现类需要添加几个注解,来拦截对应的签名:



然后实现Interceptor接口的方法即可,通过Plugin工具类方便生成代理类,通过MetaObject工具类方便操作四大对象的属性,修改对应的值。



然后实现Plugin方法,生成代理类的方法是通过MyBatis提供的Plugin工具类,它实现了InvocationHandler接口(JDK动态代理的接口),看看它的2个方法:



Plugin提供了静态方法wrap方法,它会根据插件的签名配置,使用JDK动态代理的方法,生成一个代理类,当四大对象执行方法时,会调用Plugin的invoke方法,如果方法包含在声明的签名里,就会调用自定义插件的intercept方法,传入Invocation对象。

最后,插件的初始化时在MyBatis初始化的时候完成的,读入插件节点和配置的参数,使用反射技术生成插件实例,然后调用插件方法中的setProperties方法设置参数,并将插件实例保存到配置对象中.

4、最后分享一下很不错的mybatis多租户插件,当然,你也可以自己实现

https://github.com/Mearalu/mybatis-multi-tenancy

关注小编,小编会每天为你分享有趣的技术文章哦。 偷偷告诉你私信小编“学习”会有意想不到的惊喜哟~~!

文章来源: https://www.toutiao.com/group/6720014624881672707/