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

网友投稿 453 2022-12-26

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封装

例子:

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 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);

MapResultHaSccObBndler 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

http:// */

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注解,则这里对结果进行拦截并转换

SccObB MapF2F mapF2FAnnotation = currentMethod.getAnnotation(MapF2F.class);

Statement statement = (Statement) invocation.getArgs()[0];

Pair, Class>> kvTypePair = getKVTypeOfReturnMap(currentMethod);// 获取返回Map里key-value的类型

TypeHandlerRegistry typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistrySccObB();// 获取各种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>> 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 res = new ArrayList();

Map 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;

}

/**

* 结果类型转换。

*

* 这里借用注册在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配置拦截器

2.5 简例

/**

* 批量获取用户姓名

*

* @param ids

* @return key为ID,value为username

*/

@MapF2F()

Map queryUserNamesByIds(@Param("ids") List ids);

SELECT id, user_name

FROM user_info

WHERE id IN

#{item}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java开发环境配置及Vscode搭建过程
下一篇:在线解密网站api接口(apicloud解密)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~