MyBatis 返回动态结果类型插件

原创 2016年10月16日 18:41:29

MyBatis 返回动态结果类型插件

说明

虽然写了这么一个插件,但是个人建议尽可能不去这么用,如果这个插件真正能方便你,使用起来也没任何问题。

关于插件的一些个人修改建议,在插件的注释中有说明。

插件用途:可以在 MyBatis 参数中带上要返回的类型Class,插件就会改变返回值类型为你指定的类型。

用法

说的可能不清楚,看个简单的用法。

MyBatis 中定义如下方法:

Object selectById(@Param("id")Long id, @Param("resultType")Class resultType);

//或

Object selectById(@Param("id")Long id, @Param("resultType")String resultType);

支持直接的Class或者String类型的全限定类名,必须指定参数的keyresultType,通过拦截器参数可以修改这个值,参数的顺序无所谓。

用法:

City city = (City) mapper.selectById(1L, City.class);

//或

City city = (City) mapper.selectById(1L, "tk.mybatis.model.City");

更变态直观的例子就是SQL也是动态传入${sql}这样方式的,不同SQL配不同的结果类型更能说明问题。你可以结合这篇 MyBatis 执行动态 SQL 博客使用。

如果看到这里觉得有用,你就可以继续往下看实现原理。

源码地址

http://git.oschina.net/free/Mybatis_Utils/tree/master/ResultType

虽然在git上,但我并不会长期维护这个插件。

实现原理

前面写过一篇 MyBatis Excutor 拦截器的巧妙用法,这个插件算是一个“修改MappedStatement 时解决并发的问题”可以参考复制的例子。

从上往下开始说实现。

拦截器签名:

@Intercepts(@Signature(
        type = Executor.class,
        method = "query",
        args = {
            MappedStatement.class, 
            Object.class, 
            RowBounds.class, 
            ResultHandler.class
        }
    )
)
public class ResultTypeInterceptor implements Interceptor {

拦截的Executor 的查询方法,拦截Executor的好处是自由度更高,但是难度也比其他的高,如果能够避免并发问题,实现起来会更容易。

拦截器处理代码

@Override
public Object intercept(Invocation invocation) throws Throwable {
    final Object[] args = invocation.getArgs();
    MappedStatement ms = (MappedStatement) args[0];
    Object parameterObject = args[1];
    //获取参数中设置的返回值类型
    Class resultType = getResultType(parameterObject);
    if(resultType == null){
        return invocation.proceed();
    }
    //复制ms,重设类型
    args[0] = newMappedStatement(ms, resultType);
    return invocation.proceed();
}

首先通过invocation.getArgs()可以得到当前执行方法的参数,这个参数列表和签名中定义的args中的类型是一致的。

其中第一个是(MappedStatement) args[0],第二个是参数对象parameterObject

首先要做的就是从参数对象中获得通过参数传递进来的resultType,使用 getResultType 方法获取。对参数不了解的人可能不清楚这里的参数可能是什么样,如果你想了解,可以看 深入了解MyBatis参数, 或者只是参考这个方法了解如何在这里处理参数。

得到返回值类型后,就该根据新的类型去创建一个resultMap,然后用这个新的类型根据现有的MappedStatement去创建一个新的MappedStatement,之所以创建一个新的而不是直接修改MappedStatement就是为了避免并发问题。

使用 newMappedStatement 创建新的MappedStatement对象,这个方法很重要,如果你要对MappedStatement做其他的修改,参考这个方法就可以。

通过下面代码就可以替换原有的ms :

args[0] = newMappedStatement(ms, resultType);

因为后续方式是使用参数(args)中的这个 ms,而不是 MyBatis Configuration中全局的ms,所以这里就避免了修改全局ms引起并发的问题。

虽然少数人能看到这里,但是我仍然建议,只学这段代码中的用法,尽可能不要去使用这个插件实现返回动态结果类型。直接使用会很不直观。但是呢,如果你是在开发一些通用框架方法,可以尝试在内部这么使用。

版权声明:版权归博主所有,转载请带上本文链接!联系方式:abel533@gmail.com 举报

相关文章推荐

MyBatis Excutor 拦截器的巧妙用法

这里要讲的巧妙用法是用来实现在拦截器中执行额外 MyBatis 现有方法的用法。并且会提供一个解决拦截Excutor时想要修改MappedStatement时解决并发的问题。这里假设一个场景: 实...

MyBatis 执行动态 SQL

应老婆要求写的这篇博客。大家基本上都知道如何使用 MyBatis 执行任意 SQL,使用方法很简单,例如在一个 XXMapper.xml 中: ${_parameter} 你可以如下调用:sq...

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

再探Java内存分配

这两天有个同事抓耳挠腮地纠结:Java到底是值传递还是引用传递。百思不得其姐,他将这个问题抛给大家一起讨论。于是,有的人说传值,有的人说传引用;不管哪方都觉得自己的理解是正确无误的。我觉得:要回答这个...
  • lfdfhl
  • lfdfhl
  • 2017-09-01 20:56
  • 7173

Jdbc事务以及Spring事务解惑

一、引言 Spring是一个IOC框架,在此IOC框架的基础上,提供了DAO集成,AOP事务控制,JNDI等等一系列的高级功能,个人觉得,在Spring中最值得称道的不仅仅他是一个非入侵的IOC...

程序员8月书讯

7月书讯中奖名单: zejian_《 Android编程权威指南(第3版)》 奋斗的镇屌 《Swift编程权威指南(第2版)》 bit_kaki《 Android编程权威指南...

spring+quartz新增,删除,暂停,恢复定时任务

spring配置 启动服务器后延迟启动定时任务--> 先定义SchedulerJob  javabean public class ScheduleJob { private String...

通过ApplicationContextAware加载Spring上下文环境

项目用到了ApplicationContextAware,通过它Spring容器会自动把上下文环境对象调用ApplicationContextAware接口中的setApplicationContex...

Kafka Producer机制优化-提高发送消息可靠性

名称解释:Broker:负责消息的存储和转发,也可以叫消息中介节点 Topic:每种消息的分类叫做主题(Topic)。 Partition:每一个Topic被切分为多个Partitions。背景P...

SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)

使用SSM(Spring、SpringMVC和Mybatis)已经有三个多月了,项目在技术上已经没有什么难点了,基于现有的技术就可以实现想要的功能,当然肯定有很多可以改进的地方。之前没有记录SSM整合...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)