栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

mybatis返回map结果集(mybatis返回值为map类型时怎么处理)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

mybatis返回map结果集(mybatis返回值为map类型时怎么处理)

背景

最近优化项目功能时,其中有部分老代码在mapper中动态注入了整条sql,而且这些sql都是关联了不少表的,还使用了java.util.Map接收返回结果,刚开始时没有问题,但后面场景多了之后有些关联表的字段名称是一样的,导致了返回的结果不正确,mybatis中文官网也有相关介绍。这篇文章主要通过实例(已上传github和gitee)去介绍了如何解决这些问题,但方案是在老代码改不动,重构没成本之下的无奈之举,能解决当前问题,但不建议采用。如果高人有更好的解决方法,请拯救一下我们项目吧!

模拟场景

假设有如下3张表,special_type和normal_type表是有比较多的重复字段的:

CREATE TABLE `product_info` (
  `product_id` int(11) NOT NULL AUTO_INCREMENT,
  `product_code` varchar(45) DEFAULT NULL,
  `product_name` varchar(45) DEFAULT NULL,
  `product_description` varchar(45) DEFAULT NULL,
  `cost` decimal(16,0) DEFAULT NULL,
  `price` decimal(16,0) DEFAULT NULL,
  `data_state` varchar(2) DEFAULT NULL,
  `created_by` varchar(45) DEFAULT NULL,
  `updated_by` varchar(45) DEFAULT NULL,
  `created_date` datetime DEFAULT NULL,
  `updated_date` datetime DEFAULT NULL,
  `product_type` varchar(3) DEFAULT NULL,
  PRIMARY KEY (`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='产品信息'

CREATE TABLE `special_type` (
  `type_id` int(11) NOT NULL AUTO_INCREMENT,
  `type` varchar(3) DEFAULT NULL,
  `description` varchar(45) DEFAULT NULL,
  `limit` varchar(45) DEFAULT NULL COMMENT '限制',
  PRIMARY KEY (`type_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='特殊产品类型表'

CREATE TABLE `normal_type` (
  `type_id` int(11) NOT NULL AUTO_INCREMENT,
  `type` varchar(3) DEFAULT NULL,
  `description` varchar(45) DEFAULT NULL,
  `level` int(11) DEFAULT NULL COMMENT '层级',
  PRIMARY KEY (`type_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='普通产品类型表'

而mybatis中的mapper查询语句如下,如果不做任何处理,返回的map中的type和description字段很可能不是我们想要的。

    

解决办法

在sql语句中添加标志性的描述,如9=#{mapFlag, jdbcType=DECIMAL},新增mybatis拦截器,单独特殊处理该条sql的返回结果。我们需要对ResultSetHandler进行拦截,拦截器做不到精准拦截某条statement,所以只能添加特殊描述字符去识别需要处理的结果集。拦截器代码如下:

package com.sherwin.druid.interceptor;

import com.alibaba.druid.pool.DruidPooledStatement;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.*;


@Intercepts({@Signature(type = ResultSetHandler.class,method = "handleResultSets",args = {Statement.class})})
public class MybatisInterceptor implements Interceptor {
    private static final Logger logger= LoggerFactory.getLogger(MybatisInterceptor.class);
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object arg0 = invocation.getArgs()[0];
        PreparedStatementProxyImpl preparedStatement = null;
        //因为使用了Druid,需要从DruidPooledStatement中获取到jdbc的preparedStatement
        if(arg0 instanceof DruidPooledStatement){
            DruidPooledStatement druidPooledStatement = (DruidPooledStatement) arg0;
            if(druidPooledStatement.getStatement() instanceof PreparedStatement)
                preparedStatement = (PreparedStatementProxyImpl) druidPooledStatement.getStatement();
        }
        if(preparedStatement == null)
            return invocation.proceed();
        String sql = preparedStatement.getSql();
        //获取参数,符合标志描述就处理map返回类型
        if(!sql.endsWith("9=?")){
            return invocation.proceed();
        }
        List> result = new ArrayList<>();
        //处理结果集,只需要结果不为空的数据字段
        try{
            ResultSetmetaData resultSetmetaData = preparedStatement.getmetaData();
            ResultSet rs = preparedStatement.getResultSet();
            int count = resultSetmetaData.getColumnCount();
            String columnName = null;
            while(rs.next()){
                Map resultMap = new HashMap<>();
                for(int i=1;i<=count;i++){
                    columnName = resultSetmetaData.getColumnName(i);
                    if(rs.getObject(i) != null){
                        resultMap.put(columnName, rs.getObject(i));
                    }
                }
                result.add(resultMap);
            }
        } catch (SQLException throwables) {
            logger.error(throwables.getMessage());
        }
        logger.warn(invocation.toString());
        return result;
    }
    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o,this);
    }
    @Override
    public void setProperties(Properties properties) {
        logger.warn(properties.toString());
    }
}

加上拦截器后可以从结果中看出,类型和类型描述都成功获取到了展示到页面中。

需注意问题

    有些mybatis版本是支持直接在sql中写“9=9”的,但新版本的会报如下异常,只能传参解决。项目使用了Druid管理链接池,如果使用了更高效的Hikari链接池时,需要修改拦截器的代码。如果使用了xml配置文件去配置mybatis,需要注释掉其他的mybatis的configuration,如下
    #mybatis.configuration.map-underscore-to-camel-case=true
    mybatis.config-location=classpath:mybatis-config.xml

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/773409.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号