ResultMap和ResultType在使用中的区别、MyBatis中Mapper的返回值类型

本文主要是介绍ResultMap和ResultType在使用中的区别、MyBatis中Mapper的返回值类型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在使用mybatis进行数据库连接操作时对于SQL语句返回结果的处理通常有两种方式,一种就是resultType另一种就是resultMap,下面说下我对这两者的认识和理解

resultType:当使用resultType做SQL语句返回结果类型处理时,对于SQL语句查询出的字段在相应的pojo中必须有和它相同的字段对应,而resultType中的内容就是pojo在本项目中的位置。

因此对于单表查询的话用resultType是最合适的。但是,如果在写pojo时,不想用数据库表中定义的字段名称,也是可以使用resultMap进行处理对应的。多表连接查询时,若是一对一的连接查询,那么需要新建一个pojo,pojo中包括两个表中需要查询出的所有的字段,这个地方的处理方式通常为创建一个继承一个表字段的pojo,再在里面添加另外一个表内需要查询出的字段即可。若是一对多查询时,若是使用内连接查询,则很可能出现查询出的字段有重复。使用双重for循环嵌套处理即可。

 

resultMap:当使用resultMap做SQL语句返回结果类型处理时,通常需要在mapper.xml中定义resultMap进行pojo和相应表字段的对应。

 

[java]  view plain copy
  1. <!-- 订单查询关联用户的resultMap  
  2.     将整个查询的结果映射到cn.itcast.mybatis.po.Orders中  
  3.      -->  
  4.     <resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserResultMap">  
  5.         <!-- 配置映射的订单信息 -->  
  6.         <!-- id:指定查询列中的唯 一标识,订单信息的中的唯 一标识,如果有多个列组成唯一标识,配置多个id  
  7.             column:订单信息的唯 一标识 列  
  8.             property:订单信息的唯 一标识 列所映射到Orders中哪个属性  
  9.           -->  
  10.         <id column="id" property="id"/>  
  11.         <result column="user_id" property="userId"/>  
  12.         <result column="number" property="number"/>  
  13.         <result column="createtime" property="createtime"/>  
  14.         <result column="note" property="note"/>         
  15.     </resultMap>  

 

 

resultMap对于一对一表连接的处理方式通常为在主表的pojo中添加嵌套另一个表的pojo,然后在mapper.xml中采用association节点元素进行对另一个表的连接处理。例如:

 

[html]  view plain copy
  1. <!-- 订单查询关联用户的resultMap  
  2.     将整个查询的结果映射到cn.itcast.mybatis.po.Orders中  
  3.      -->  
  4.     <resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserResultMap">  
  5.         <!-- 配置映射的订单信息 -->  
  6.         <!-- id:指定查询列中的唯 一标识,订单信息的中的唯 一标识,如果有多个列组成唯一标识,配置多个id  
  7.             column:订单信息的唯 一标识 列  
  8.             property:订单信息的唯 一标识 列所映射到Orders中哪个属性  
  9.           -->  
  10.         <id column="id" property="id"/>  
  11.         <result column="user_id" property="userId"/>  
  12.         <result column="number" property="number"/>  
  13.         <result column="createtime" property="createtime"/>  
  14.         <result column="note" property=note/>  
  15.           
  16.         <!-- 配置映射的关联的用户信息 -->  
  17.         <!-- association:用于映射关联查询单个对象的信息  
  18.         property:要将关联查询的用户信息映射到Orders中哪个属性  
  19.          -->  
  20.         <association property="user"  javaType="cn.itcast.mybatis.po.User">  
  21.             <!-- id:关联查询用户的唯 一标识  
  22.             column:指定唯 一标识用户信息的列  
  23.             javaType:映射到user的哪个属性  
  24.              -->  
  25.             <id column="user_id" property="id"/>  
  26.             <result column="username" property="username"/>  
  27.             <result column="sex" property="sex"/>  
  28.             <result column="address" property="address"/>  
  29.           
  30.         </association>  
  31.     </resultMap>  


若是一对多的表连接方式,比如订单表和订单明细表即为一对多连接,若是不对sql语句进行处理,由于一个订单对应多条订单明细,因此查询出的结果对于订单表数据来说将会出现重复,例如:

 

resultMap的处理方式为在订单表数据的pojo中添加一个list,list中为订单明细表的属性,在mapper.xml中采用如下的处理方式:

 

[html]  view plain copy
  1. !-- 订单及订单明细的resultMap  
  2.     使用extends继承,不用在中配置订单信息和用户信息的映射  
  3.      -->  
  4.     <resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersAndOrderDetailResultMap" extends="OrdersUserResultMap">  
  5.         <!-- 订单信息 -->  
  6.         <!-- 用户信息 -->  
  7.         <!-- 使用extends继承,不用在中配置订单信息和用户信息的映射 -->  
  8.           
  9.           
  10.         <!-- 订单明细信息  
  11.         一个订单关联查询出了多条明细,要使用collection进行映射  
  12.         collection:对关联查询到多条记录映射到集合对象中  
  13.         property:将关联查询到多条记录映射到cn.itcast.mybatis.po.Orders哪个属性  
  14.         ofType:指定映射到list集合属性中pojo的类型  
  15.          -->  
  16.          <collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">  
  17.             <!-- id:订单明细唯 一标识  
  18.             property:要将订单明细的唯 一标识 映射到cn.itcast.mybatis.po.Orderdetail的哪个属性  
  19.               -->  
  20.             <id column="orderdetail_id" property="id"/>  
  21.             <result column="items_id" property="itemsId"/>  
  22.             <result column="items_num" property="itemsNum"/>  
  23.             <result column="orders_id" property="ordersId"/>  
  24.          </collection>  
  25.           
  26.       
  27.     </resultMap>  


在查询时,虽然一条订单信息对应多条订单明细,由于将多条信息明细存储到了list中,因此查询后将不再出现重复数据,达到了去重的效果

 

 

----------------------------------------------------------------------------------------------------------------

对数据库执行修改操作时,数据库会返回受影响的行数。

在MyBatis(使用版本3.4.6,早期版本不支持)中insert、update、delete语句的返回值可以是Integer、Long和Boolean。在定义Mapper接口时直接指定需要的类型即可,无需在对应的<insert><update><delete>标签中显示声明。

对应的代码在 org.apache.ibatis.binding.MapperMethod 类中,如下:

  • 对于insert、update、delete语句,MyBatis都会使用 rowCountResult 方法对返回值进行转换;
  • rowCountResult 方法会根据Mapper声明中方法的返回值类型来对参数进行转换;
  • 对于返回类型为Boolean的情况,如果返回的值大于0,则返回True,否则返回False
 1 public Object execute(SqlSession sqlSession, Object[] args) {2     Object result;3     switch (command.getType()) {4       case INSERT: {5       Object param = method.convertArgsToSqlCommandParam(args);6         result = rowCountResult(sqlSession.insert(command.getName(), param));7         break;8       }9       case UPDATE: {
10         Object param = method.convertArgsToSqlCommandParam(args);
11         result = rowCountResult(sqlSession.update(command.getName(), param));
12         break;
13       }
14       case DELETE: {
15         Object param = method.convertArgsToSqlCommandParam(args);
16         result = rowCountResult(sqlSession.delete(command.getName(), param));
17         break;
18       }
19       case SELECT:
20         if (method.returnsVoid() && method.hasResultHandler()) {
21           executeWithResultHandler(sqlSession, args);
22           result = null;
23         } else if (method.returnsMany()) {
24           result = executeForMany(sqlSession, args);
25         } else if (method.returnsMap()) {
26           result = executeForMap(sqlSession, args);
27         } else if (method.returnsCursor()) {
28           result = executeForCursor(sqlSession, args);
29         } else {
30           Object param = method.convertArgsToSqlCommandParam(args);
31           result = sqlSession.selectOne(command.getName(), param);
32         }
33         break;
34       case FLUSH:
35         result = sqlSession.flushStatements();
36         break;
37       default:
38         throw new BindingException("Unknown execution method for: " + command.getName());
39     }
40     if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
41       throw new BindingException("Mapper method '" + command.getName() 
42           + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
43     }
44     return result;
45   }
46 
47   private Object rowCountResult(int rowCount) {
48     final Object result;
49     if (method.returnsVoid()) {
50       result = null;
51     } else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
52       result = rowCount;
53     } else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
54       result = (long)rowCount;
55     } else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
56       result = rowCount > 0;
57     } else {
58       throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
59     }
60     return result;
61   }

select语句的返回值类型

对于select语句,必须在Mapper映射文件中显示声明返回值类型,否则会抛出异常,指出“A query was run and no Result Maps were found for the Mapped Statement”。

  • 返回Integer或Long类型
    • 与修改语句不同,select语句必须指定返回值类型,且mapper映射文件中的返回值类型需要与mapper接口中声明的返回值类型一致,都是int或long;
    • mapper接口中的返回值类型可以是Integer、Long,也可以是int、long
  • 不能返回Boolean类型

   select语句不能返回Boolean类型

  • 返回自定义类型的Bean

  select语句返回的column值与Mapper方法返回值的属性的映射有两种方式(具体设置见下文):

    • 通过名称实现自动映射
    • 通过resultMap标签指定映射方式
  • 返回List、Set、Array类型

   直接指定select方法的返回值为List<T>、Set<T>、即可,注意此时mapper映射文件中select标签的 resultType类型一定要是自定义的Bean类型,而不是集合类型,可以理解为resultType指定的类型对应的是数据库中的一行数据

  • 返回Map类型

   返回Map类型有两种含义:

    • resultType的类型为map,mapper接口的返回值也为Map,此时返回结果将Bean的属性作为key,值作为Value返回
    • resultType的类型为非map类型(自定义类型、数值类型、String等),mapper接口的返回值为Map,且指定了mapKey,此时的返回结果以指定的mapKey作为Key,以resultType类型对象作为value

通过column别名实现自定义类型的自动映射

只要保证数据库查询返回的column名称和Bean的属性名一致,Mybatis便能够实现自动映射。如:

    <select id="selectActorById"  resultType="canger.study.chapter04.bean.Actor">select actor_id as id, first_name as firstName ,last_name as lastNamefrom actorwhere actor_id=#{id}</select>
public class Actor {Long id;String firstName;String lastName;
}

 需要特别说明的有3个地方:

  1. 返回值Bean无需为属性设置getter/setter方法,Mybatis依然能够为其赋值;
  2. 如果column名称和Bean的属性名只有部分相同,那么只有名称相同的属性会被赋值,Bean依然会被创建;
  3. 如果column名称与所有Bean的属性名都不相同,则select语句会返回null值,即使数据库中存在符合查询条件的记录;

设置mapUnderscoreToCamelCase属性实现自动映射

    <settings><setting name="mapUnderscoreToCamelCase" value="true"/></settings>

 

  • 如果数据库采用了严格的under score命名规则,则通过设置mapUnderscoreToCamelCase属性并可实现column到实体类property的自动映射;
  • 实际项目中,可将命名不规范的column通过resultMap进行显示声明,符合命名规范的进行自动映射

 通过resultMap标签指定自定义类型的映射方式

 需要在mapper映射文件中定义 resultMap标签

    <resultMap id="actorResultMap" type="canger.study.chapter04.bean.Actor"><id column="id" property="id" jdbcType="BIGINT" javaType="long" typeHandler="org.apache.ibatis.type.LongTypeHandler"/><result column="firstName" property="firstName" jdbcType="VARCHAR" javaType="string" typeHandler="org.apache.ibatis.type.StringTypeHandler"/><result column="lastName" property="lastName" jdbcType="VARCHAR" javaType="string" typeHandler="org.apache.ibatis.type.StringTypeHandler"/></resultMap>

 

    <select id="selectActorById"  resultMap="actorResultMap">select actor_id as id, first_name as firstName ,last_name as lastNamefrom actorwhere actor_id=#{id}</select>

 

需要注意的几点

  • id或result标签中的column属性一定要使用SQL select 语句中最终返回到数据库客户端的列名,如对于select actor_id as id,在resultMap中需要使用 id而不是 actor_id;
  • 无需将查询返回的所有column都进行显示声明,没有在resultMap中声明映射关系的column将进行自动映射
  • typeHandler属性:如果使用MyBatis提供的typeHandler,则一定要是用全类名,MyBatis默认没有为typeHandler其注册别名;
  • jdbcType 、 javaType和typeHandler的对照关系,以及jdbcType和数据库类型的对照关系参见 Mybatis中jdbcType和javaType、typeHandler的对照关系
  • MyBatis注册的默认TypeHandler参见类 org.apache.ibatis.type.TypeHandlerRegistry,具体如下
public TypeHandlerRegistry() {register(Boolean.class, new BooleanTypeHandler());register(boolean.class, new BooleanTypeHandler());register(JdbcType.BOOLEAN, new BooleanTypeHandler());register(JdbcType.BIT, new BooleanTypeHandler());register(Byte.class, new ByteTypeHandler());register(byte.class, new ByteTypeHandler());register(JdbcType.TINYINT, new ByteTypeHandler());register(Short.class, new ShortTypeHandler());register(short.class, new ShortTypeHandler());register(JdbcType.SMALLINT, new ShortTypeHandler());register(Integer.class, new IntegerTypeHandler());register(int.class, new IntegerTypeHandler());register(JdbcType.INTEGER, new IntegerTypeHandler());register(Long.class, new LongTypeHandler());register(long.class, new LongTypeHandler());register(Float.class, new FloatTypeHandler());register(float.class, new FloatTypeHandler());register(JdbcType.FLOAT, new FloatTypeHandler());register(Double.class, new DoubleTypeHandler());register(double.class, new DoubleTypeHandler());register(JdbcType.DOUBLE, new DoubleTypeHandler());register(Reader.class, new ClobReaderTypeHandler());register(String.class, new StringTypeHandler());register(String.class, JdbcType.CHAR, new StringTypeHandler());register(String.class, JdbcType.CLOB, new ClobTypeHandler());register(String.class, JdbcType.VARCHAR, new StringTypeHandler());register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());register(String.class, JdbcType.NCHAR, new NStringTypeHandler());register(String.class, JdbcType.NCLOB, new NClobTypeHandler());register(JdbcType.CHAR, new StringTypeHandler());register(JdbcType.VARCHAR, new StringTypeHandler());register(JdbcType.CLOB, new ClobTypeHandler());register(JdbcType.LONGVARCHAR, new ClobTypeHandler());register(JdbcType.NVARCHAR, new NStringTypeHandler());register(JdbcType.NCHAR, new NStringTypeHandler());register(JdbcType.NCLOB, new NClobTypeHandler());register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());register(JdbcType.ARRAY, new ArrayTypeHandler());register(BigInteger.class, new BigIntegerTypeHandler());register(JdbcType.BIGINT, new LongTypeHandler());register(BigDecimal.class, new BigDecimalTypeHandler());register(JdbcType.REAL, new BigDecimalTypeHandler());register(JdbcType.DECIMAL, new BigDecimalTypeHandler());register(JdbcType.NUMERIC, new BigDecimalTypeHandler());register(InputStream.class, new BlobInputStreamTypeHandler());register(Byte[].class, new ByteObjectArrayTypeHandler());register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());register(byte[].class, new ByteArrayTypeHandler());register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());register(JdbcType.LONGVARBINARY, new BlobTypeHandler());register(JdbcType.BLOB, new BlobTypeHandler());register(Object.class, UNKNOWN_TYPE_HANDLER);register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);register(Date.class, new DateTypeHandler());register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());register(JdbcType.TIMESTAMP, new DateTypeHandler());register(JdbcType.DATE, new DateOnlyTypeHandler());register(JdbcType.TIME, new TimeOnlyTypeHandler());register(java.sql.Date.class, new SqlDateTypeHandler());register(java.sql.Time.class, new SqlTimeTypeHandler());register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());// mybatis-typehandlers-jsr310if (Jdk.dateAndTimeApiExists) {this.register(Instant.class, InstantTypeHandler.class);this.register(LocalDateTime.class, LocalDateTimeTypeHandler.class);this.register(LocalDate.class, LocalDateTypeHandler.class);this.register(LocalTime.class, LocalTimeTypeHandler.class);this.register(OffsetDateTime.class, OffsetDateTimeTypeHandler.class);this.register(OffsetTime.class, OffsetTimeTypeHandler.class);this.register(ZonedDateTime.class, ZonedDateTimeTypeHandler.class);this.register(Month.class, MonthTypeHandler.class);this.register(Year.class, YearTypeHandler.class);this.register(YearMonth.class, YearMonthTypeHandler.class);this.register(JapaneseDate.class, JapaneseDateTypeHandler.class);}

 ------------------------------------------------------------------------------------------------------------------

Mybatis返回值类型为List时,sql语句怎么写

前言:

因为某个需求需要返回访问数据库的返回值是每条记录的同一列,所以就想到了用集合。List<String>.然后就开始操作。。。

代码一开始是这样的

<!--查询所有老师-->
<select id="findTeacherName" resultMap="java.lang.String" >
select
<include refid="Teacher_Name" />
from teacher
</select>
好像没什么错误,而且项目运行了也没报错。重点是项目没报错,但接着想登录的时候就失败了,虽然登录功能不在同一个XxxMapper.xml。但似乎访问数据库的功能都失败。

这时候就很纠结了,因为也没报错。找了一整天登录功能出现什么问题,还是没解决。

后来想了想,把之前代码删掉,似乎可以了。于是看之前加的上面的代码,看了也没错啊,返回值是java.lang.String。百度也很多说是这个类型,根据之前学的也是一样。

终于。。。发现问题所在了

后来变成这样

<!--查询所有老师-->
<select id="findTeacherName" resultType="java.lang.String" >
select
<include refid="Teacher_Name" />
from teacher
</select>
红色的才是重点。。。
---------------------
作者:小神兜兜
来源:CSDN
原文:https://blog.csdn.net/weixin_41746397/article/details/89430162

转载于:https://www.cnblogs.com/xiaoshen666/p/11117980.html

这篇关于ResultMap和ResultType在使用中的区别、MyBatis中Mapper的返回值类型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/426266

相关文章

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

破茧 JDBC:MyBatis 在 Spring Boot 中的轻量实践指南

《破茧JDBC:MyBatis在SpringBoot中的轻量实践指南》MyBatis是持久层框架,简化JDBC开发,通过接口+XML/注解实现数据访问,动态代理生成实现类,支持增删改查及参数... 目录一、什么是 MyBATis二、 MyBatis 入门2.1、创建项目2.2、配置数据库连接字符串2.3、入

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

python使用try函数详解

《python使用try函数详解》Pythontry语句用于异常处理,支持捕获特定/多种异常、else/final子句确保资源释放,结合with语句自动清理,可自定义异常及嵌套结构,灵活应对错误场景... 目录try 函数的基本语法捕获特定异常捕获多个异常使用 else 子句使用 finally 子句捕获所

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali