1. why

  项目没有使用MyBatis,进行数据操作时使用的是jdbc中默认的schema,现在项目要加入多租户,同一个数据库下不同租户使用不同的实例schema,这就要在mapper文件内所有的表名称前加上schema,并动态传递其参数值,这样每个SQL都要添加这个参数,如果传递的是对象,也要给对象加相应的属性,这个工作量可想而知。
  必须想办法,将schema参数传递给所有的SQL,办法就是全局配置。

2. code

2.1 实现拦截器接口并重写方法

拦截器【 1️⃣ SchemaInterceptor】实现(如果用户调用的SQL接口里没有传 schemaName 就用默认值):

@Intercepts({@Signature(method = "update",args = {MappedStatement.class, Object.class}, type = Executor.class),@Signature(method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}, type = Executor.class)
})
public class SchemaInterceptor implements Interceptor {/*** 这里没有打印日志*/private static Log LOG = LogFactory.getLog(SchemaInterceptor.class);/*** mapper.xml 使用SCHEMA时的参数名称*/private static final String SCHEMA = "schemaName";/*** 设置默认的schema*/private String schema = "public";/*** 拦截到的动态SQL处理后放入此对象*/private Set<Integer> sourceStorage = new HashSet<>();@Overridepublic Object intercept(Invocation invocation) throws Throwable {Object[] args = invocation.getArgs();MappedStatement mappedStatement = (MappedStatement) args[0];SqlSource sqlSource = mappedStatement.getSqlSource();// 只拦截动态SQLif (sqlSource instanceof DynamicSqlSource) {// 获取到sqlNode对象Field field = DynamicSqlSource.class.getDeclaredField("rootSqlNode");field.setAccessible(true);SqlNode sqlNode = (SqlNode) field.get(sqlSource);if (!sourceStorage.contains(sqlSource.hashCode())) {// 获取动态代理对象Map<String, Object> argMap = (HashMap<String, Object>) args[1];// 判断是否传递 schemaName或schema 如果已经传递则使用用户传递的值 否则使用默认值String schemaNameStr = "schemaName", schemaStr = "schema";if (StringUtils.isEmpty(MapUtils.getString(argMap, schemaNameStr)) && StringUtils.isEmpty(MapUtils.getString(argMap, schemaStr))) {SqlNode proxyNode = proxyNode(sqlNode);field.set(sqlSource, proxyNode);}sourceStorage.add(sqlSource.hashCode());}}return invocation.proceed();}/*** 通过动态代理对象 添加schema参数** @param sqlNode SQL节点* @return SqlNode*/private SqlNode proxyNode(SqlNode sqlNode) {return (SqlNode) Proxy.newProxyInstance(sqlNode.getClass().getClassLoader(),new Class[]{SqlNode.class}, new SqlNodeInvocationHandler(sqlNode));}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {LOG.debug("setProperties====>" + properties);}private class SqlNodeInvocationHandler implements InvocationHandler {private SqlNode target;SqlNodeInvocationHandler(SqlNode target) {super();this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {DynamicContext context = (DynamicContext) args[0];// 给schema添加.setSchema(schema);// 设置schemacontext.getBindings().put(SCHEMA, schema);return method.invoke(target, args);}}/*** 给schema 添加.** @param schema schemaName*/private void setSchema(String schema) {String pointStr = ".";if (StringUtils.isNotBlank(schema)) {if (!schema.endsWith(pointStr)) {schema += pointStr;}}this.schema = schema;}
}

2.2 拦截器注册

拦截器【 2️⃣ 注册】给 SqlSessionFactoryBean 添加插件:

    @Bean(name = "sqlSessionFactory_greenplum")@Primarypublic SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource_greenplum") DataSource dataSource)throws Exception {final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();// 设置数据源参数sessionFactory.setDataSource(dataSource);// mapper路径和mybatis配置文件路径sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(GreenplumConfiguration.MAPPER_LOCATION));sessionFactory.setConfigLocation(new ClassPathResource(mybatisConfigPath));// 添加自定义的schema拦截器【此次配置的重点】sessionFactory.setPlugins(new Interceptor[]{new SchemaInterceptor()});return sessionFactory.getObject();}

2.3 拦截器注入参数使用

注入【 3️⃣ mapper.xml】这里使用 ${schemaName} 获取配置的 schema 的值:

<!--执行插入文件数据SQL-->
<insert id="insertFileData" parameterType="map">insert into ${schemaName}${target_table}( ${table_field} ) VALUES ( ${field_value} )
</insert>

3. 总结

首先要注意的是,这里用的不是SpringMVC里的拦截器,而是mybatis的拦截器,拦截器是在执行mapper文件内的SQL前触发的,此时,如果你传递了schema参数,拦截器就不会覆盖schema的值,如果没有配置,则使用配置的默认值。

【Java代码】使用 org.apache.ibatis.plugin.Interceptor 拦截器实现全局 mapper.xml 参数注入(可用于切换数据库实例schema+Demo举例源码)相关推荐

  1. com.github.pagehelper.PageHelper cannot be cast to org.apache.ibatis.plugin.Interceptor

    使用pagehelper插件时异常       5.0之后的版本使用com.github.pagehelper.PageInterceptor这个类 即改为:         <plugin i ...

  2. Mybatis Interceptor 拦截器

    拦截器(Interceptor)在 Mybatis 中被当做插件(plugin)对待,官方文档提供了 Executor(拦截执行器的方法),ParameterHandler(拦截参数的处理),Resu ...

  3. 求助--报错:Caused by: java.lang.ClassCastException: org.apache.ibatis.type.InstantTypeHandler cannot be

    这里写自定义目录标题 问题描述: 问题描述: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creat ...

  4. Exception in thread “main“ java.lang.NoClassDefFoundError: org/apache/ibatis/io/Resources

    项目场景: 在学习mybatis框架的时候,刚刚学习如果查询数据库user表中的信息时 问题描述: 所有步骤都是按照教程上走的,但是运行后里面就出现了 Exception in thread &quo ...

  5. 一次java.lang.ClassNotFoundException: org.apache.ibatis.session.SqlSession异常解决

    一次整合框架时,出现找不到类的异常,如下图所示 java.lang.NoClassDefFoundError: org/apache/ibatis/session/SqlSession 详细报错信息如 ...

  6. Mybatis笔记一:java.lang.NoClassDefFoundError: org/apache/ibatis/mapping/DatabaseIdProvider

    异常错误:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSess ...

  7. java.lang.ClassNotFoundException: org.apache.ibatis.session.SqlSession

    默默记录一个被自己蠢死的错误!!! 原本可以运行的项目突然报错了..!!然后自己很纳闷,因为什么都没有改,就排了两个jar冲突,百思不得其解..然后各种百度各种找问题,就是死活找不到..知道后来认认真 ...

  8. java lang NoClassDefFoundError org/apache/ibatis/session/Sq

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 1.错误 ...

  9. java.lang.NoClassDefFoundError: org/apache/ibatis/io/Resources

    关于 idea 中 mybatis 项目 报错:NoClassDefFoundError 的问题: - 需要将需要的包导入到输出的文件夹中 - 但是idea 不会默认导进去 - 导致在部署项目的时候l ...

最新文章

  1. Cannot run program /opt/CI/android-sdk-linux/build-tools/26.0.0/aapt: error=13, Permission denied
  2. vim 命令模式 筛选_10个步骤的筛选器模式
  3. 《Bash 脚本教程》免费发布啦,开源!
  4. python函数中的关键字参数
  5. 构造方法之间如何调用?
  6. 有趣的小事——程序员难!
  7. 1200PLC学习资料整理
  8. 常用Word 排版要求
  9. 如何在前端html获取cookie
  10. sql自定义报表软件_SQL Server中的报表–自定义报表的外观
  11. 5个SEO网站优化的技巧
  12. 2022年制冷与空调设备运行操作最新解析及制冷与空调设备运行操作作业考试题库
  13. Python 下载视频出错 you-get: [error] oops, something went wrong.
  14. php curl curlopt_customrequest,php – 如何重置CURLOPT_CUSTOMREQUEST
  15. C# 获取MP3/WMA音频数据信息
  16. java 机器人模拟人工操作_Java制作自动访问网站机器人!(转)
  17. html页面加载有时没有网样式,网站css样式不加载是什么原因?
  18. jxl可以操作excel2007吗?可以
  19. linux美化文件,Linux 终端美化 - Oh My Zsh
  20. Android 字体库详解

热门文章

  1. JVM-Java程序性能监控-初级篇
  2. error C3872: '0x3000': this character is not allowed in an identifier 解决方法
  3. 移动搜索引擎-网页信息预处理
  4. 用于正则表达式的 Regex.Matches静态方法的几种用法
  5. ASP.NET AJAX深入浅出系列课程
  6. android 上下扫描动画,Android扫描雷达动画
  7. js 对一个字段去重_JS单行、多行文本字符去重和行去重
  8. rz安装 xshell_利用XShell上传、下载文件(使用sz与rz命令)
  9. oracle 保留一个记录吗,笔记:Oracle查询重复数据并删除,只保留一条记录
  10. CSS美化网页元素大全