mybatis resulttype如何获取List<Object[]>

mybatis resulttype如何获取List<Object[]>,第1张

mybatis resulttype返回类型,一般list的话,如果就实体类型,返回你上面定义的参数类型就可以,像list,按照map返就行,resultType="javautilMap",你是不需要考虚list中包含的类型的

<select id="countDistinctOrder" parameterType="javautilMap" resultType="javalangInteger">

select

count(1)

from table

where

</select>

KeyWords: Mybatis 原理,源码,Mybatis Mapper 接口实现类,代理模式,动态代理,Java动态代理,ProxynewProxyInstance,Mapper 映射,Mapper 实现

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。我们在使用 Mybaits 进行 ,通常只需要定义几个 Mapper 接口,然后在编写一个 xml 文件,我们在配置文件中写好 sql , Mybatis 帮我们完成 Mapper 接口道具体实现的调用。以及将结果映射到 model bean 中。

我们在项目中所编写的众多的 Mapper 类只是一个接口(interface ),根据 Java 的多态性我们知道,可以使用接口接口作为形参,进而在运行时确定具体实现的对象是什么。但是,对于 Mapper 接口,我们并没有编写其实现类!Mybatis是如何找到其实现类,进而完成具体的 CRUD 方法调用的呢?原理何在?

为了弄清楚 Mapper 接口是如何找到实现类的,我们先回忆一下 Mybatis 是怎么使用的,根据实际的例子,进而一点点的去分析。这里的使用指的是Mybatis 单独使用,而不是整合 spring , 因为整合 spring 的话,还需要涉及 Mapper dao 装载到 spring 容器的问题,spring 帮忙创建数据源配置等问题。

通常我们使用 Mybatis 的主要步骤是:

从一段代码看起

上面我们概括了使用 Mybatis 的4个步骤。这4个步骤看起来很简单,但是用代码写出来就很多。我们不妨先记着这4个步骤,再去看代码,会容易点。

在这块代码中,第 1 部分我们使用了 Java 编码的形式来实现 SqlSessionFactory ,也可以使用 xml 。如果使用xml的话,上面的第一部分代码就是这样的:

我们本次的目标是弄清楚 “ Mapper 是如何找到实现类的 ”,我们注意上面代码 3 , 4 的位置:

这里 mapper 可以调用selectBlog(1) 这个方法,说明 mapper 是个对象,因为对象才具有方法行为实现啊。BlogMapper接口是不能实例化的,更没有具体方法实现。我们并没有定义一个类,让它实现BlogMapper接口,而在这里它只是通过调用sessiongetMapper() 所得到的。由此,我们可以推断:肯定是sessiongetMapper() 方法内部产生了BlogMapper的实现类。有什么技术可以根据BlogMapper 接口生成了一个实现类呢?想到这里,对于有动态代理 使用经验的程序员来说,很容易想到,这背后肯定是基于动态代理技术,具体怎么实现的呢?下面我们来根据源码一探究竟。

Mapper 接口的注册

从上面的代码中,我们知道 BlogMapper 接口的实现类是从sessiongetMapper中得来的,大概是基于动态代理技术实现。我们既然能够从SqlSession中得到BlogMapper接口的,那么我们肯定需要先在哪里把它放进去了,然后 SqlSession 才能生成我们想要的代理类啊。上面代码中有这么一行:

跟着这个 addMapper 方法的代码实现是这样的:

我们看到这里 mapper 实际上被添加到 mapperRegissry 中。继续跟进代码:

看到这里我们知道上面所执行的configurationaddMapper(BlogMapperclass); 其实最终被放到了HashMap中,其名为knownMappers ,knowMappers是MapperRegistry 类的一个私有属性,它是一个HashMap 。其Key 为当前Class对象,value 为一个MapperProxyFactory 实例。

这里我们总结一下: 诸如BlogMapper 之类的Mapper接口被添加到了MapperRegistry 中的一个HashMap中。并以 Mapper 接口的 Class 对象作为 Key , 以一个携带Mapper接口作为属性的MapperProxyFactory 实例作为value 。MapperProxyFacory从名字来看,好像是一个工厂,用来创建Mapper Proxy的工厂。我们继续往下看。

Mapper接口的动态代理类的生成

上面我们已经知道,Mapper 接口被到注册到了MapperRegistry中——放在其名为knowMappers 的HashMap属性中,我们在调用Mapper接口的方法的时候,是这样的:

这里,我们跟踪一下sessiongetMapper() 方法的代码实现,这里 SqlSession 是一个接口,他有两个实现类,一个是DefaultSqlSession,另外一个是SqlSessionManager,这里我们用的是DefaultSqlSession 为什么是DefaultSqlSession呢?因为我们在初始化SqlSessionFactory的时候所调用的SqlSessionFactoryBuilder的build()方法里边配置的就是DefaultSqlSession, 所以,我们进入到DefaultSession类中,看看它对sessiongetMapper(BlogMapperclass)是怎么实现的:

如代码所示,这里的 getMapper 调用了 configurationgetMapper , 这一步 *** 作其实最终是调用了MapperRegistry,而此前我们已经知道,MapperRegistry是存放了一个HashMap的,我们继续跟踪进去看看,那么这里的get,肯定是从这个hashMap中取数据。我们来看看代码:

我们调用的sessiongetMapper(BlogMapperclass);最终会到达上面这个方法,这个方法,根据BlogMapper的class对象,以它为key在knowMappers 中找到了对应的value —— MapperProxyFactory(BlogMapper) 对象,然后调用这个对象的newInstance()方法。根据这个名字,我们就能猜到这个方法是创建了一个对象,代码是这样的:

看到这里,就清楚了,最终是通过ProxynewProxyInstance产生了一个BlogMapper的代理对象。Mybatis 为了完成 Mapper 接口的实现,运用了代理模式。具体是使用了JDK动态代理,这个ProxynewProxyInstance方法生成代理类的三个要素是:

代理模式中,代理类(MapperProxy)中才真正的完成了方法调用的逻辑。我们贴出MapperProxy的代码,如下:

我们调用的 Blog blog = mapperselectBlog(1); 实际上最后是会调用这个MapperProxy的invoke方法。这段代码中,if 语句先判断,我们想要调用的方法是否来自Object类,这里的意思就是,如果我们调用toString()方法,那么是不需要做代理增强的,直接还调用原来的methodinvoke()就行了。只有调用selectBlog()之类的方法的时候,才执行增强的调用——即mapperMethodexecute(sqlSession, args);这一句代码逻辑。

而mapperMethodexecute(sqlSession, args);这句最终就会执行增删改查了,代码如下:

再往下一层,就是执行JDBC那一套了,获取链接,执行,得到ResultSet,解析ResultSet映射成JavaBean。

至此,我们已经摸清楚了Blog blog = mapperselectBlog(1); 中,BlogMapper接口调用到得到数据库数据过程中,Mybaitis 是如何为接口生成实现类的,以及在哪里出发了最终的CRUD调用。实际上,如果我们在调用Blog blog = mapperselectBlog(1);之前,把从slqSession中得到的 mapper 对象打印出来就会看到,输出大概是这样的:

动态代理没错吧,Java动态代理实在是太美妙了。

上面我们用层层深入的方式摸清楚了 Mapper接口是如何找到实现类的。我们分析了 Mapper接口是如何注册的,Mapper接口是如何产生动态代理对象的,Maper接口方法最终是如何执行的。总结起来主要就是这几个点:

*** 作。具体的步骤如下:

获取 MyBatis 中的 MappedStatement 对象。可以通过 SqlSession 的 getConfiguration() 方法获取 Configuration 对象,然后再通过 Configuration 对象的 getMappedStatement() 方法获取 MappedStatement 对象。

从 MappedStatement 对象中获取 BoundSql 对象,即 SQL 语句绑定的参数对象。

从 BoundSql 对象中获取 SQL 语句字符串。可以通过调用 getSql() 方法获取 SQL 语句字符串。

对 SQL 语句进行相应的 *** 作。例如,可以对 SQL 语句进行修改、输出等 *** 作。

Java 通过反射获取 MyBatis 中的 SQL 语句的代码示例:

SqlSession sqlSession = sqlSessionFactoryopenSession();

try {

// 获取 MappedStatement 对象

MappedStatement mappedStatement = sqlSessiongetConfiguration()getMappedStatement("comexamplemapperselectUser");

// 获取 BoundSql 对象

BoundSql boundSql = mappedStatementgetBoundSql(paramObject);

// 获取 SQL 语句字符串

String sql = boundSqlgetSql();

// 对 SQL 语句进行相应的 *** 作

//

} finally {

sqlSessionclose();

}

需要注意的是,在使用反射获取 SQL 语句时,要注意保护用户隐私和安全,以免发生 SQL 注入等问题。

  在对 ObjectWrapper 类的介绍中,除了 #hasGetter 、 #hasSetter 、 #getGetterType 、 #getSetterType 这几个方法,其余带 PropertyTokenizer 类型参数的方法中,参数代表的表达式已经是经过解析没有子表达式的形式了如 order[0] ,最终在 ObjectWrapper 中完成功能实现的最后一环,而表达式带多层子表达式的初始状态的解析过程正是在 MetaObject 类中进行的,对 MetaObject 的分析,聚焦于这个属性表达式的解析过程。

解析

  如果传入的对象是一个 ObjectWrapper 则直接使用,否则尝试用 ObjectWrapperFactory 创建 ObjectWrapper(假如用户自定义实现可用),如果以上情况都不满足,则先后尝试创建与对象类型相匹配的 ObjectWrapper,可选类型为 MapWrapper CollectionWrapper BeanWrapper

功能创建 MetaObject 对象的静态方法,也是唯一调用途径,因为构造方法为 private。

源码与注解

解析

  如果原始Java对象不为空,则调用构造方法创建对象,否则,使用特殊的用来表达原始对象为空的 SystemMetaObjectNULL_META_OBJECT , SystemMetaObject 类的定义如下:

功能获取表达式指定的原始对象中属性的值。

源码与注解

解析

  递归处理表达式的处理跟 ObjectWrapper 中的 #hasGetter 、 #hasSetter 、 #getGetterType 、 #getSetterType 类似,MetaClass 类中有个方法 #metaClassForProperty() 用来为对象属性创建对应的 MetaClass 对象,同样的 MetaObject 类中也有方法 #metaObjectForProperty() 用来为对象属性创建对应的 MetaObject 对象,其源码如下:

功能为表达式指定的原始对象中属性设置值。

源码与注解

解析

   #setValue() 跟 #getValue() 差别在于:如果顶层属性为空,肯定无法获取值,直接返回null;但是设置属性值,即使顶层属性为空,也可以先初始化顶层属性,再赋值。比如 userorderamount ,属性 user 是一个 User 对象,order 是其成员,类型为 Order,如果 order 为空,获取值时 order 的 amount 成员也必为空,但是设置值时,即使 order 为空,也可以先创建对象 order = new Order() 再给 orderamount 赋值。

  除了上述方法,其他方法只是类中定义属性的一个简单的 getter,或者是对 ObjectWrapper 接口方法的一个代理,方便外部程序直接调用 MetaObject 类中的方法就可以实现相应的功能。

以上就是关于mybatis resulttype如何获取List<Object[]>全部的内容,包括:mybatis resulttype如何获取List<Object[]>、mybatis 如何获取返回的条数、Mybatis Mapper接口是如何找到实现类的-源码分析等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9816047.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-02
下一篇 2023-05-02

发表评论

登录后才能评论

评论列表(0条)

保存