sql查询返回值使用map封装多个key和value实例
直接上代码,代码是测试过的
1.重写ResultHandler
public class MapResultHandler implements ResultHandler {private final Map mappedResults = new HashMap(); @Overridepublic void handleResult(ResultContext context) {@SuppressWarnings("rawtypes")Map map = (Map) context.getResultObject(); mappedResults.put(map.get("key"), map.get("value")); }public Map getMappedResults() {return mappedResults; }}
2.在mapper封装
例子:
SELECT F_NAME keyName,nvl(sum (F_METADATA_VALUE),0) val from 表名GROUP BY F_CODE, F_NAME
3.service实现
@Autowiredprivate SqlSessionFactory sqlSessionFactory; private static final String mapperPath = "mapper的路径."; Map parameter = new HashMap<>(); //设置参数parameter.put("query", query); //mapper的方法名String methodName = "selectMedicineSurvey"; //查询数据使用Map封装Map medicineSurveyMap = getStringBigDecimalMap(mapperPath, parameter, methodName); //查询数据使用Map封装private Map getStringBigDecimalMap(String mapperPath, Map parameter, String methodName) {SqlSession sqlSession = sqlSessionFactory.openSession(true); MapResultHandler handler = new MapResultHandler(); sqlSession.select(mapperPath + methodName, parameter, handler); //关流sqlSession.close(); //获取结果return (Map) handler.getMappedResults(); }
sqlSession.close();
一定要记得数据库关流,不然连接数就会把数据库给卡死
MyBatis查询两个字段,返回Map,一个字段作为key,一个字段作为value的实现
1. 问题描述 在使用MyBatis,我们经常会遇到这种情况:SELECT两个字段,需要返回一个Map,其中第一个字段作为key,第二个字段作为value。MyBatis的MapKey虽然很实用,但并不能解决这种场景。这里,就介绍一种使用拦截器来解决这个问题的方案。
2. 解决方案 源码详见:spring-mybatis-test
2.1 注解
package com.adu.spring_test.mybatis.annotations; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 将查询结果映射成map的注解,其中第一个字段为key,第二个字段为value. * * 注:返回类型必须为{@link java.util.Map Map}。K/V的类型通过MyBatis的TypeHander进行类型转换,如有必要可自定义TypeHander。 * * @author yunjie.du * @date 2016/12/22 18:44 */@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.METHOD })public @interface MapF2F {/*** 是否允许key重复。如果不允许,而实际结果出现了重复,会抛出org.springframework.dao.DuplicateKeyException。* * @return*/boolean isAllowKeyRepeat() default true; /*** 对于相同的key,是否允许value不同(在允许key重复的前提下)。如果允许,则按查询结果,后面的覆盖前面的;如果不允许,则会抛出org.springframework.dao.DuplicateKeyException。* * @return*/boolean isAllowValueDifferentWithSameKey() default false; }
【sql查询返回值使用map封装多个key和value实例】2.2 拦截器
package com.adu.spring_test.mybatis.interceptor; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Properties; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.executor.resultset.ResultSetHandler; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.type.TypeHandler; import org.apache.ibatis.type.TypeHandlerRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.DuplicateKeyException; import com.adu.spring_test.mybatis.annotations.MapF2F; import com.adu.spring_test.mybatis.util.ReflectUtil; import javafx.util.Pair; /** * MapF2F的拦截器 * * @author yunjie.du * @date 2016/12/22 18:44 */@Intercepts(@Signature(method = "handleResultSets", type = ResultSetHandler.class, args = { Statement.class }))public class MapF2FInterceptor implements Interceptor {private Logger logger = LoggerFactory.getLogger(MapF2FInterceptor.class); @Overridepublic Object intercept(Invocation invocation) throws Throwable {MetaObject metaStatementHandler = ReflectUtil.getRealTarget(invocation); MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("mappedStatement"); String className = StringUtils.substringBeforeLast(mappedStatement.getId(), "."); // 当前类String currentMethodName = StringUtils.substringAfterLast(mappedStatement.getId(), "."); // 当前方法Method currentMethod = findMethod(className, currentMethodName); // 获取当前Methodif (currentMethod == null || currentMethod.getAnnotation(MapF2F.class) == null) {// 如果当前Method没有注解MapF2Freturn invocation.proceed(); }// 如果有MapF2F注解,则这里对结果进行拦截并转换MapF2F mapF2FAnnotation = currentMethod.getAnnotation(MapF2F.class); Statement statement = (Statement) invocation.getArgs()[0]; Pair, Class>> kvTypePair = getKVTypeOfReturnMap(currentMethod); // 获取返回Map里key-value的类型TypeHandlerRegistry typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry(); // 获取各种TypeHander的注册器return result2Map(statement, typeHandlerRegistry, kvTypePair, mapF2FAnnotation); }@Overridepublic Object plugin(Object obj) {return Plugin.wrap(obj, this); }@Overridepublic void setProperties(Properties properties) {}/*** 找到与指定函数名匹配的Method。** @param className* @param targetMethodName* @return* @throws Throwable*/private Method findMethod(String className, String targetMethodName) throws Throwable {Method[] methods = Class.forName(className).getDeclaredMethods(); // 该类所有声明的方法if (methods == null) {return null; }for (Method method : methods) {if (StringUtils.equals(method.getName(), targetMethodName)) {return method; }}return null; }/*** 获取函数返回Map中key-value的类型* * @param mapF2FMethod* @return left为key的类型,right为value的类型*/private Pair , Class>> getKVTypeOfReturnMap(Method mapF2FMethod) {Type returnType = mapF2FMethod.getGenericReturnType(); if (returnType instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) returnType; if (!Map.class.equals(parameterizedType.getRawType())) {throw new RuntimeException("[ERROR-MapF2F-return-map-type]使用MapF2F,返回类型必须是java.util.Map类型!!!method=" + mapF2FMethod); }return new Pair<>((Class>) parameterizedType.getActualTypeArguments()[0],(Class>) parameterizedType.getActualTypeArguments()[1]); }return new Pair<>(null, null); }/*** 将查询结果映射成Map,其中第一个字段作为key,第二个字段作为value.* * @param statement* @param typeHandlerRegistry MyBatis里typeHandler的注册器,方便转换成用户指定的结果类型* @param kvTypePair 函数指定返回Map key-value的类型* @param mapF2FAnnotation* @return* @throws Throwable*/private Object result2Map(Statement statement, TypeHandlerRegistry typeHandlerRegistry,Pair , Class>> kvTypePair, MapF2F mapF2FAnnotation) throws Throwable {ResultSet resultSet = statement.getResultSet(); List
2.3 ReflectUtil
package com.adu.spring_test.mybatis.util; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.SystemMetaObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 反射工具类 */public class ReflectUtil {private static final Logger logger = LoggerFactory.getLogger(ReflectUtil.class); /*** 分离最后一个代理的目标对象* * @param invocation* @return*/public static MetaObject getRealTarget(Invocation invocation) {MetaObject metaStatementHandler = SystemMetaObject.forObject(invocation.getTarget()); while (metaStatementHandler.hasGetter("h")) {Object object = metaStatementHandler.getValue("h"); metaStatementHandler = SystemMetaObject.forObject(object); }while (metaStatementHandler.hasGetter("target")) {Object object = metaStatementHandler.getValue("target"); metaStatementHandler = SystemMetaObject.forObject(object); }return metaStatementHandler; }}
2.4 MyBatis Datasource配置拦截器
2.5 简例
/** * 批量获取用户姓名 * * @param ids * @return key为ID,value为username */@MapF2F()MapqueryUserNamesByIds(@Param("ids") List ids);
SELECT id, user_nameFROM user_infoWHERE id IN#{item}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
推荐阅读
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- mybatisplus如何在xml的连表查询中使用queryWrapper
- mybatisplus|mybatisplus where QueryWrapper加括号嵌套查询方式
- MybatisPlus使用queryWrapper如何实现复杂查询
- py连接mysql
- 2019-01-18Mysql中主机名的问题
- MySql数据库备份与恢复
- 前端代码|前端代码 返回顶部 backToTop
- mysql|InnoDB数据页结构
- 数据库|SQL行转列方式优化查询性能实践