insert、update、delete语句的返回值类型

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

在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
 public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
} private Object rowCountResult(int rowCount) {
final Object result;
if (method.returnsVoid()) {
result = null;
} else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
result = rowCount;
} else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
result = (long)rowCount;
} else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
result = rowCount > 0;
} else {
throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
}
return result;
}

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 lastName
from actor
where 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 lastName
from actor
where 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-jsr310
if (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中Mapper的返回值类型的更多相关文章

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

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

  2. MyBatis查询结果resultType返回值类型详细介绍

    一.返回一般数据类型 比如要根据 id 属性获得数据库中的某个字段值. mapper 接口: // 根据 id 获得数据库中的 username 字段的值 String getEmpNameById( ...

  3. mybatis 中的 update 返回值

    摘自:https://www.jianshu.com/p/80270b93082a 如果定义一个如下的update函数,那么这个函数的返回值到底是啥意思呢?是受影响的行数吗? 验证之前我们先看看数据库 ...

  4. SpringMVC中Controller的返回值类型

    Controller方法的返回值可以有以下几种: 1.返回ModelAndView 返回ModelAndView时最常见的一种返回结果.需要在方法结束的时候定义一个ModelAndView对象,并对M ...

  5. mvc中actionresult的返回值类型

    以前一直没注意actionresult都能返回哪些类型的类型值(一直用的公司的内部工具类初始化进行返回的),今天跟大家分享一下(也是转载的别人的日志qaq). 首先我们了解一下对action的要求: ...

  6. C#中部分方法返回值类型为什么只能是void?

    这个问题答案选至<C#入门经典> 如果方法具有返回类型,那就可以作为表达式的一部分: x=Manipulate(y,z); 如果没有给部分方法提供实现代码,编译器就会在使用该方法的所有地方 ...

  7. mybatis 中的 update 返回值你真的明白吗

    记录源地址:https://www.jianshu.com/p/80270b93082a

  8. int不可为null引发的 MyBatis做持久层框架,返回值类型要为Integer问题

    MyBatis做持久层框架,返回值类型要为Integer MyBatis 做持久层时,之前没注意,有时候为了偷懒使用了int类型做为返回的类型,这样是不可取的,MyBatis做持久层框架,返回值类型要 ...

  9. Asp.net MVC 中Controller返回值类型ActionResult

    [Asp.net MVC中Controller返回值类型] 在mvc中所有的controller类都必须使用"Controller"后缀来命名并且对Action也有一定的要求: 必 ...

随机推荐

  1. DNS主从复制及子域(三)

    主从DNS 主辅DNS服务器数据同步的过程,首先master DNS服务器每 次修改完成并重启服务后,将传送notify给所有的Slave DNS服务器. Slave DNS服务器将查询Master服 ...

  2. redis主从搭建

    两台服务器 127.0.0.101 A 主服务器 127.0.0.108 B 从服务器 从服务器设置 1.修改redis.conf 依次修改daemonize no改为daemonize yes  默 ...

  3. HDU1599(Floyd最小环)

    Floyd最小环理解+模板: https://www.cnblogs.com/DF-yimeng/p/8858184.html 除了上述博文里写的,我再补充几点我的理解. 1.为什么先枚举ij求经过i ...

  4. Java java.text.ParseException: Unparseable date

    用java将字符串转换成Date类型是,会出现java.text.ParseException: Unparseable date异常. 例如下面的这段代码就会出现上面的异常: public bool ...

  5. 在ASP.NET Core上实施每个租户策略的数据库

    在ASP.NET Core上实施每个租户策略的数据库 不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: http://g ...

  6. SharePoint2016配置工作流开发环境

    1,下载Web PlatForm5.0  地址:https://www.microsoft.com/web/downloads/platform.aspx 2,保证开发环境能连网,安装Web Plat ...

  7. mfc 友元类

    知识点 继承类成员的访问级别 友元类 继承访问控制: 基类 派生类(能否访问) public private protected 派生类类 派生类对象 派生类 派生类对象 派生类类 派生类对象 pri ...

  8. Codeforces 955C Sad powers (数论)

    题目链接:Sad powers 题意:给出n个l和r,求出每个给出的[l,r]之间的可以使是另外一个数的k次方的数.(k>=2) 题解:题目给出的数据范围最大是1E18所以如果要直接把所有的从1 ...

  9. R语言学习 第三篇:数据框

    数据框(data.frame)是最常用的数据结构,用于存储二维表(即关系表)的数据,每一列存储的数据类型必须相同,不同数据列的数据类型可以相同,也可以不同,但是每列的行数(长度)必须相同.数据框的每列 ...

  10. Redis发布订阅和事物笔记

    Redis 发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. Redis 客户端可以订阅任意数量的频道. 下图展示了频道 cha ...