sql查詢返回值使用map封裝多個(gè)key和value實(shí)例
直接上代碼,代碼是測試過的
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)文章
MyBatis中XML 映射文件中常見的標(biāo)簽說明
這篇文章主要介紹了MyBatis中XML 映射文件中常見的標(biāo)簽說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07JAVA中方法的聲明及使用方式(繼承、多態(tài)、封裝)
這篇文章主要介紹了JAVA中方法的聲明及使用方式(繼承、多態(tài)、封裝),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02詳解Spring Boot實(shí)現(xiàn)日志記錄 SLF4J
本篇文章主要介紹了詳解Spring Boot實(shí)現(xiàn)日志記錄 SLF4J,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05java排查進(jìn)程占用系統(tǒng)內(nèi)存高方法
這篇文章主要為大家介紹了java進(jìn)程占用系統(tǒng)內(nèi)存高排查方法,2023-06-06