mybatis查询结果返回至实体类

本文详细解析了在使用MyBatis进行查询时出现的java.util.HashMap无法转换为实体类的问题,并提供了两种解决方案:一是正确设置resultType属性,二是将查询结果的Map集合转换为实体对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

近期,利用mybatis做一个简单查询,先看主要代码:

Service层:

package com.example1.service;

import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example1.dao.OrderMapper;
import com.example1.pojo.Order;

@Service
public class OrderService {
	
	private Logger log = Logger.getLogger(OrderService.class);

	@Autowired
	private OrderMapper orderMapper;
	
	public void findOrders() {
		List<Order> orders = orderMapper.findOrders();
		for (Order order : orders) {
			log.info(order.getId() + " : " + order.getName());
		}
	}
}

dao层:

package com.example1.dao;

import java.util.List;

import com.example1.pojo.Order;

public interface OrderMapper {

	public List<Order> findOrders();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example1.dao.OrderMapper">

	<select id="findOrders" parameterType="String" resultType="java.util.Map">
		SELECT * FROM t_order 
	</select>
</mapper>

Order类:

package com.example1.pojo;

public class Order {

	private String id;
	private String name;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Order [id=" + id + ", name=" + name + "]";
	}
}

配置妥当,执行,结果报错了:

java.lang.ClassCastException: java.util.HashMap cannot be cast to com.example1.pojo.Order
	at com.example1.service.OrderService.findOrders(OrderService.java:26)
	at com.example1.service.OrderService$$FastClassBySpringCGLIB$$b6b2c61a.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
	at com.example1.service.OrderService$$EnhancerBySpringCGLIB$$e285c4bb.findOrders(<generated>)
	at com.example1.controller.OrderController.findOrders(OrderController.java:22)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:100)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:604)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:565)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
	at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:879)
	at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:617)
	at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1778)
	at java.lang.Thread.run(Thread.java:745)

可以看出,java.util.HashMap不能直接存储到具体的实体类。

解决办法:

一、dao层通过resultType指定返回类型

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example1.dao.OrderMapper">

	<select id="findOrders" parameterType="String" resultType="com.example1.pojo.Order">
		SELECT * FROM t_order 
	</select>
</mapper>

二、查询结果返回list,然后遍历list,将map转换成相应的java对象

修改后的Service层:

package com.example1.service;

import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example1.dao.OrderMapper;
import com.example1.pojo.Order;

@Service
public class OrderService {
	
	private Logger log = Logger.getLogger(OrderService.class);

	@Autowired
	private OrderMapper orderMapper;
	
	public void findOrders() {
		List<Map> orders = orderMapper.findOrders();
		for (Map orderMap : orders) {
			String orderJsonStr = JSONObject.toJSONString(orderMap);
			Order order = (Order) JSONArray.parseObject(orderJsonStr,Order.class);
			log.info(order.getId() + " : " + order.getName());
		}
	}
}

dao层:

package com.example1.dao;

import java.util.List;
import java.util.Map;

public interface OrderMapper {

	public List<Map> findOrders();
}

其中,关于map转java对象的方法有好多种,具体可以参考本人另一篇文章:

https://blog.youkuaiyun.com/liuyunyihao/article/details/86597002

以上两种方法均实际测试通过。

 

 

<think>好的,我现在需要帮助用户了解如何在MyBatis中将查询结果装入多个实体类。首先,我得回忆一下MyBatis的相关知识,特别是结果映射的部分。用户提到的“多个实体类”可能是指一个查询返回的数据需要分配到不同的Java对象中,比如关联查询或者包含多个对象的情况。 接下来,我需要确定用户可能遇到的具体场景。通常,这种情况出现在联表查询时,比如查询订单信息同时包含用户信息,这时候结果需要分别映射到Order和User两个实体类。或者,可能是一个查询结果中的不同字段需要分组到不同的对象中,比如统计信息分散在多个实体中。 然后,我应该考虑MyBatis中处理这种情况的几种方法。常见的有两种:使用association标签处理一对一关联,或者使用resultMap进行复杂的映射。另外,可能还需要提到动态SQL或者嵌套查询,但用户的问题更侧重于结果映射,所以association和resultMap的组合可能是重点。 需要确保覆盖到不同的情况。比如,如果一个结果集对应多个实体类,每个实体类对应其中的一部分字段,这时候需要在resultMap中定义各个实体的属性,并通过association或collection来关联。如果是多个结果集,可能需要使用MyBatis的@MapKey注解或者resultMap的extends属性,但可能用户指的是单次查询返回多个实体的情况。 另外,可能用户对MyBatis的基础已经有所了解,但需要更高级的映射技巧。因此,我应该给出具体的例子,比如如何编写XML中的resultMap,如何使用association标签,以及对应的Java实体类结构。同时,需要注意字段别名在SQL中的使用,确保数据库列名能够正确映射到实体类的属性。 可能还需要提到注解方式,虽然XML配置更灵活,但注解方式在某些简单情况下也可以使用。不过,处理复杂映射通常推荐XML配置。另外,是否需要提到嵌套查询(通过select属性)?比如,先查询实体,然后通过另一个查询加载关联实体,但这可能会导致N+1查询问题,所以需要权衡。 此外,是否需要处理集合属性,比如一对多的情况?用户的问题是关于多个实体类,可能包括一对一的关联,也可能包括包含多个对象的情况,所以可能需要区分这两种情况,分别给出示例。 最后,要确保语言通俗易懂,步骤清晰,让用户能够按照示例进行操作。可能需要检查是否有遗漏的情况,或者是否有更简便的方法。比如,使用自动映射配合别名,如果数据库列名和实体属性名能够对应的话,可能不需要显式配置resultMap,但这种情况可能只适用于单一实体,无法处理多个实体的情况。因此,显式配置resultMap还是必要的。 总结一下,步骤应该是:1. 创建各个实体类;2. 在XML中编写resultMap,使用association或collection标签;3. SQL查询中使用别名对应实体属性;4. 在接口中定义方法。同时给出示例代码,这样用户更容易理解。</think>在MyBatis中将查询结果映射到多个实体类,通常通过以下两种方式实现: --- ### 一、使用 `resultMap` + `association` 标签(一对一关联) **适用场景**:查询结果包含多个关联实体(如订单关联用户) #### 1. 定义实体类 ```java // 订单实体 public class Order { private Long id; private String orderNo; private User user; // 关联用户实体 // getter/setter } // 用户实体 public class User { private Long userId; private String userName; // getter/setter } ``` #### 2. XML映射配置 ```xml <resultMap id="orderWithUserMap" type="Order"> <!-- 映射Order本身的字段 --> <id property="id" column="order_id"/> <result property="orderNo" column="order_no"/> <!-- 通过association映射关联的User对象 --> <association property="user" javaType="User"> <id property="userId" column="user_id"/> <result property="userName" column="user_name"/> </association> </resultMap> <select id="getOrderWithUser" resultMap="orderWithUserMap"> SELECT o.id as order_id, o.order_no, u.id as user_id, u.name as user_name FROM orders o LEFT JOIN user u ON o.user_id = u.id WHERE o.id = #{id} </select> ``` --- ### 二、使用 `resultMap` + 多个`association`(多实体组合) **适用场景**:查询结果需要拆分到多个无关联的实体 #### 1. 定义实体类 ```java public class ReportDTO { private SalesData salesData; private UserInfo userInfo; // getter/setter } public class SalesData { private Integer totalAmount; private Date reportDate; } public class UserInfo { private String region; private String department; } ``` #### 2. XML映射配置 ```xml <resultMap id="combinedResultMap" type="ReportDTO"> <!-- 映射SalesData对象 --> <association property="salesData" javaType="SalesData"> <result property="totalAmount" column="total_amount"/> <result property="reportDate" column="report_date"/> </association> <!-- 映射UserInfo对象 --> <association property="userInfo" javaType="UserInfo"> <result property="region" column="user_region"/> <result property="department" column="user_dept"/> </association> </resultMap> <select id="getCombinedReport" resultMap="combinedResultMap"> SELECT s.total_amount, s.report_date, u.region as user_region, u.department as user_dept FROM sales s JOIN users u ON s.user_id = u.id </select> ``` --- ### 三、通过字段别名自动映射 **适用场景**:简单场景下快速映射(需严格保持命名一致) ```sql <select id="getCombinedData" resultType="map"> SELECT a.field1 as "dataA.field1", a.field2 as "dataA.field2", b.field3 as "dataB.field3" FROM table_a a JOIN table_b b ON a.id = b.a_id </select> ``` 在Java层手动处理: ```java public class Service { public void processResult(Map<String, Object> map) { DataA dataA = new DataA(); dataA.setField1((String) map.get("dataA.field1")); DataB dataB = new DataB(); dataB.setField3((Integer) map.get("dataB.field3")); } } ``` --- ### 四、扩展技巧 1. **嵌套查询**:通过`<association select="">`实现延迟加载 2. **集合映射**:使用`<collection>`处理一对多关系 3. **继承映射**:通过`extends`属性复用resultMap > 建议:复杂场景优先使用`resultMap`显式映射,保证可维护性。通过合理的SQL别名设计和结果映射配置,可以实现任意复杂的对象组装需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值