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

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

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

phoenix

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

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

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

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

phoenix

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

!-- 订单及订单明细的resultMap

使用extends继承,不用在中配置订单信息和用户信息的映射

-->

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

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

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

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

对应的代码在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、Set、即可,注意此时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 actor_id as id, first_name as firstName ,last_name as lastName

from actor

where actor_id=#{id}

public class Actor {

Long id;

String firstName;

String lastName;

}

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

返回值Bean无需为属性设置getter/setter方法,Mybatis依然能够为其赋值;

如果column名称和Bean的属性名只有部分相同,那么只有名称相同的属性会被赋值,Bean依然会被创建;

如果column名称与所有Bean的属性名都不相同,则select语句会返回null值,即使数据库中存在符合查询条件的记录;

设置mapUnderscoreToCamelCase属性实现自动映射

如果数据库采用了严格的under score命名规则,则通过设置mapUnderscoreToCamelCase属性并可实现column到实体类property的自动映射;

实际项目中,可将命名不规范的column通过resultMap进行显示声明,符合命名规范的进行自动映射

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

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

typeHandler="org.apache.ibatis.type.StringTypeHandler"/>

typeHandler="org.apache.ibatis.type.StringTypeHandler"/>

select actor_id as id, first_name as firstName ,last_name as lastName

from actor

where actor_id=#{id}

需要注意的几点

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注册的默认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返回值类型为List时,sql语句怎么写

前言:

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

代码一开始是这样的

select

from teacher

好像没什么错误,而且项目运行了也没报错。重点是项目没报错,但接着想登录的时候就失败了,虽然登录功能不在同一个XxxMapper.xml。但似乎访问数据库的功能都失败。

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

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

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

后来变成这样

select

from teacher

红色的才是重点。。。

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

作者:小神兜兜

来源:CSDN

原文:https://blog.csdn.net/weixin_41746397/article/details/89430162

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值