sql查询返回值使用map封装多个key和value实例

直接上代码,代码是测试过的

1.重写ResultHandler

public class MapResultHandler implements ResultHandler {    private final Map mappedResults = new HashMap();    @Override    public 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封装

  <resultMap id="retMap" type="java.util.HashMap">        <result column="keyName" property="key" javaType="java.lang.String"/>        <result column="val" property="value" javaType="java.math.BigDecimal"/>    </resultMap> 

例子:

SELECT F_NAME keyName,nvl(sum (F_METADATA_VALUE),0) val from 表名GROUP BY F_CODE, F_NAME

3.service实现

 @Autowired    private SqlSessionFactory sqlSessionFactory;    private static final String mapperPath = "mapper的路径.";        Map<String, Object> parameter = new HashMap<>();  //设置参数        parameter.put("query", query);  //mapper的方法名        String methodName = "selectMedicineSurvey";        //查询数据使用Map封装        Map<String, BigDecimal> medicineSurveyMap = getStringBigDecimalMap(mapperPath, parameter, methodName);    //查询数据使用Map封装    private Map<String, BigDecimal> getStringBigDecimalMap(String mapperPath, Map<String, Object> parameter, String methodName) {        SqlSession sqlSession = sqlSessionFactory.openSession(true);        MapResultHandler handler = new MapResultHandler();        sqlSession.select(mapperPath + methodName, parameter, handler);       //关流        sqlSession.close();         //获取结果        return (Map<String, BigDecimal>) 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. * <p> * 注:返回类型必须为{@link java.util.Map Map<K, V>}。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;}

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);    @Override    public 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);// 获取当前Method        if (currentMethod == null || currentMethod.getAnnotation(MapF2F.class) == null) {// 如果当前Method没有注解MapF2F            return invocation.proceed();        }        // 如果有MapF2F注解,则这里对结果进行拦截并转换        MapF2F mapF2FAnnotation = currentMethod.getAnnotation(MapF2F.class);        Statement statement = (Statement) invocation.getArgs()[0];        Pair<Class<?>, Class<?>> kvTypePair = getKVTypeOfReturnMap(currentMethod);// 获取返回Map里key-value的类型        TypeHandlerRegistry typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();// 获取各种TypeHander的注册器        return result2Map(statement, typeHandlerRegistry, kvTypePair, mapF2FAnnotation);    }    @Override    public Object plugin(Object obj) {        return Plugin.wrap(obj, this);    }    @Override    public 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<?>, 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<?>, Class<?>> kvTypePair, MapF2F mapF2FAnnotation) throws Throwable {        ResultSet resultSet = statement.getResultSet();        List<Object> res = new ArrayList();        Map<Object, Object> map = new HashMap();        while (resultSet.next()) {            Object key = this.getObject(resultSet, 1, typeHandlerRegistry, kvTypePair.getKey());            Object value = this.getObject(resultSet, 2, typeHandlerRegistry, kvTypePair.getValue());            if (map.containsKey(key)) {// 该key已存在                if (!mapF2FAnnotation.isAllowKeyRepeat()) {// 判断是否允许key重复                    throw new DuplicateKeyException("MapF2F duplicated key!key=" + key);                }                Object preValue = map.get(key);                if (!mapF2FAnnotation.isAllowValueDifferentWithSameKey() && !Objects.equals(value, preValue)) {// 判断是否允许value不同                    throw new DuplicateKeyException("MapF2F different value with same key!key=" + key + ",value1="                            + preValue + ",value2=" + value);                }            }            map.put(key, value);// 第一列作为key,第二列作为value。        }        res.add(map);        return res;    }    /**     * 结果类型转换。     * <p>     * 这里借用注册在MyBatis的typeHander(包括自定义的),方便进行类型转换。     *      * @param resultSet     * @param columnIndex 字段下标,从1开始     * @param typeHandlerRegistry MyBatis里typeHandler的注册器,方便转换成用户指定的结果类型     * @param javaType 要转换的Java类型     * @return     * @throws SQLException     */    private Object getObject(ResultSet resultSet, int columnIndex, TypeHandlerRegistry typeHandlerRegistry,            Class<?> javaType) throws SQLException {        final TypeHandler<?> typeHandler = typeHandlerRegistry.hasTypeHandler(javaType)                ? typeHandlerRegistry.getTypeHandler(javaType) : typeHandlerRegistry.getUnknownTypeHandler();        return typeHandler.getResult(resultSet, columnIndex);    }}

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配置拦截器

<!-- session factory -->    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">        <property name="dataSource" ref="dataSource" />        <property name="configLocation" value="classpath:mybatis/mybatis-data-config.xml" />        <property name="mapperLocations" value="classpath:mapper/**/*.xml" />        <property name="plugins">            <array>                <bean class="com.adu.spring_test.mybatis.interceptor.MapF2FInterceptor"/>            </array>        </property>    </bean>

2.5 简例

/** * 批量获取用户姓名 * * @param ids * @return key为ID,value为username */@MapF2F()Map<Long, String> queryUserNamesByIds(@Param("ids") List<Long> ids);
<select id="queryUserNamesByIds" resultType="map">    SELECT id, user_name    FROM user_info    WHERE id IN        <foreach collection="ids" open="(" close=")" separator="," item="item">            #{item}        </foreach></select>

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

爱情不是避难所,想进去避难的话,是会被赶出来的。

sql查询返回值使用map封装多个key和value实例

相关文章:

你感兴趣的文章:

标签云: