欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

sql查詢返回值使用map封裝多個(gè)key和value實(shí)例

 更新時(shí)間:2021年07月19日 10:02:59   作者:幾癡~  
這篇文章主要介紹了sql查詢返回值使用map封裝多個(gè)key和value實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

直接上代碼,代碼是測試過的

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實(shí)現(xiàn)

 @Autowired
    private SqlSessionFactory sqlSessionFactory;
    private static final String mapperPath = "mapper的路徑.";      
  Map<String, Object> parameter = new HashMap<>();
  //設(shè)置參數(shù)
        parameter.put("query", query);
  //mapper的方法名
        String methodName = "selectMedicineSurvey";
        //查詢數(shù)據(jù)使用Map封裝
        Map<String, BigDecimal> medicineSurveyMap = getStringBigDecimalMap(mapperPath, parameter, methodName);
    //查詢數(shù)據(jù)使用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);
       //關(guān)流
        sqlSession.close();
         //獲取結(jié)果
        return (Map<String, BigDecimal>) handler.getMappedResults();
    }
sqlSession.close();

一定要記得數(shù)據(jù)庫關(guān)流,不然連接數(shù)就會(huì)把數(shù)據(jù)庫給卡死

MyBatis查詢兩個(gè)字段,返回Map,一個(gè)字段作為key,一個(gè)字段作為value的實(shí)現(xiàn)

1. 問題描述

在使用MyBatis,我們經(jīng)常會(huì)遇到這種情況:SELECT兩個(gè)字段,需要返回一個(gè)Map,其中第一個(gè)字段作為key,第二個(gè)字段作為value。MyBatis的MapKey雖然很實(shí)用,但并不能解決這種場景。這里,就介紹一種使用攔截器來解決這個(gè)問題的方案。

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;
/**
 * 將查詢結(jié)果映射成map的注解,其中第一個(gè)字段為key,第二個(gè)字段為value.
 * <p>
 * 注:返回類型必須為{@link java.util.Map Map<K, V>}。K/V的類型通過MyBatis的TypeHander進(jìn)行類型轉(zhuǎn)換,如有必要可自定義TypeHander。
 *
 * @author yunjie.du
 * @date 2016/12/22 18:44
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface MapF2F {
    /**
     * 是否允許key重復(fù)。如果不允許,而實(shí)際結(jié)果出現(xiàn)了重復(fù),會(huì)拋出org.springframework.dao.DuplicateKeyException。
     * 
     * @return
     */
    boolean isAllowKeyRepeat() default true;
    /**
     * 對(duì)于相同的key,是否允許value不同(在允許key重復(fù)的前提下)。如果允許,則按查詢結(jié)果,后面的覆蓋前面的;如果不允許,則會(huì)拋出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(), ".");// 當(dāng)前類
        String currentMethodName = StringUtils.substringAfterLast(mappedStatement.getId(), ".");// 當(dāng)前方法
        Method currentMethod = findMethod(className, currentMethodName);// 獲取當(dāng)前Method
        if (currentMethod == null || currentMethod.getAnnotation(MapF2F.class) == null) {// 如果當(dāng)前Method沒有注解MapF2F
            return invocation.proceed();
        }
        // 如果有MapF2F注解,則這里對(duì)結(jié)果進(jìn)行攔截并轉(zhuǎn)換
        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的注冊(cè)器
        return result2Map(statement, typeHandlerRegistry, kvTypePair, mapF2FAnnotation);
    }
    @Override
    public Object plugin(Object obj) {
        return Plugin.wrap(obj, this);
    }
    @Override
    public void setProperties(Properties properties) {
    }
    /**
     * 找到與指定函數(shù)名匹配的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;
    }
    /**
     * 獲取函數(shù)返回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);
    }
    /**
     * 將查詢結(jié)果映射成Map,其中第一個(gè)字段作為key,第二個(gè)字段作為value.
     * 
     * @param statement
     * @param typeHandlerRegistry MyBatis里typeHandler的注冊(cè)器,方便轉(zhuǎn)換成用戶指定的結(jié)果類型
     * @param kvTypePair 函數(shù)指定返回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重復(fù)
                    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;
    }
    /**
     * 結(jié)果類型轉(zhuǎn)換。
     * <p>
     * 這里借用注冊(cè)在MyBatis的typeHander(包括自定義的),方便進(jìn)行類型轉(zhuǎn)換。
     * 
     * @param resultSet
     * @param columnIndex 字段下標(biāo),從1開始
     * @param typeHandlerRegistry MyBatis里typeHandler的注冊(cè)器,方便轉(zhuǎn)換成用戶指定的結(jié)果類型
     * @param javaType 要轉(zhuǎn)換的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);
    /**
     * 分離最后一個(gè)代理的目標(biāo)對(duì)象
     * 
     * @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>

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • IDEA查看Scala的源碼的教程圖解

    IDEA查看Scala的源碼的教程圖解

    這篇文章主要介紹了IDEA查看Scala的源碼的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 淺談JVM垃圾回收之哪些對(duì)象可以被回收

    淺談JVM垃圾回收之哪些對(duì)象可以被回收

    這篇文章主要介紹了JVM垃圾回收之哪些對(duì)象可以被回收,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Java IO流 File類的常用API實(shí)例

    Java IO流 File類的常用API實(shí)例

    這篇文章主要介紹了Java IO流 File類的常用API實(shí)例的相關(guān)資料,需要的朋友參考下吧
    2017-05-05
  • MyBatis中XML 映射文件中常見的標(biāo)簽說明

    MyBatis中XML 映射文件中常見的標(biāo)簽說明

    這篇文章主要介紹了MyBatis中XML 映射文件中常見的標(biāo)簽說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java Spring事務(wù)的隔離級(jí)別詳解

    Java Spring事務(wù)的隔離級(jí)別詳解

    這篇文章主要介紹了Java Spring事務(wù)的隔離級(jí)別,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • JAVA中方法的聲明及使用方式(繼承、多態(tài)、封裝)

    JAVA中方法的聲明及使用方式(繼承、多態(tài)、封裝)

    這篇文章主要介紹了JAVA中方法的聲明及使用方式(繼承、多態(tài)、封裝),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • JVM之內(nèi)存分配和回收機(jī)制

    JVM之內(nèi)存分配和回收機(jī)制

    本篇主要介紹JVM內(nèi)存分配和回收策略,內(nèi)容主要節(jié)選自《深入理解java虛擬機(jī)》,需要的朋友可以參考下
    2023-05-05
  • 詳解Spring Boot實(shí)現(xiàn)日志記錄 SLF4J

    詳解Spring Boot實(shí)現(xiàn)日志記錄 SLF4J

    本篇文章主要介紹了詳解Spring Boot實(shí)現(xiàn)日志記錄 SLF4J,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • java排查進(jìn)程占用系統(tǒng)內(nèi)存高方法

    java排查進(jìn)程占用系統(tǒng)內(nèi)存高方法

    這篇文章主要為大家介紹了java進(jìn)程占用系統(tǒng)內(nèi)存高排查方法,
    2023-06-06
  • 一文帶你搞懂Java中i++ 和 ++i的區(qū)別

    一文帶你搞懂Java中i++ 和 ++i的區(qū)別

    在Java中,i++和++i都用于遞增變量i的值,但它們之間有一個(gè)細(xì)微的區(qū)別,i++是后綴遞增操作符,++i是前綴遞增操作符,在大多數(shù)情況下,這兩種遞增操作的結(jié)果都是一樣的,但在某些特定的表達(dá)式和邏輯中,它們可能會(huì)產(chǎn)生不同的效果,本文將帶大家搞清Java中i++ 和 ++i的區(qū)別
    2023-09-09

最新評(píng)論