mybatis中foreach重复使用一个对象的问题

2023-12-09 00:08

本文主要是介绍mybatis中foreach重复使用一个对象的问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

需求:在一个非常夸张的SQL中,出现了一个需求点,在这个SQL中需要将同一个collection对象进行多次循环输出。

画外音:该SQL不能重构,改了恐怕会错的更多,只能采取打补丁的方式,等待下一个接收这个SQL的人员,哈哈。

出现的问题:

本人采取foreach的方式来遍历该集合对象,整个SQL看起来像这样

select id,name from A
where
name in
<foreach item="item" collection="myList" separator="," open="(" close=")" index="">#{item}
</foreach>unionselect id,name from B
where
name in
<foreach item="item" collection="myList" separator="," open="(" close=")" index="">#{item}
</foreach>

对于第一次出现的循环,打印出的SQL结果是正常的,但是第二次出现的循环却找不到内容,感觉这个对象好像不存在了。

排查方法:

1、当然是在网上找有没有类似的问题撒,参考了这个文档https://blog.csdn.net/weixin_30549657/article/details/96281457,修改了item的名称,发现还是木有效果

2、从源码角度来找问题源头,根据网上大神们的源码解读,找到了ExpressionEvaluator这个类,贴出的部分源码就是对集合对象进行SQL动态替换的入口

public Iterable<?> evaluateIterable(String expression, Object parameterObject) {Object value = OgnlCache.getValue(expression, parameterObject);if (value == null) throw new BuilderException("The expression '" + expression + "' evaluated to a null value.");if (value instanceof Iterable) return (Iterable<?>) value;if (value.getClass().isArray()) {// the array may be primitive, so Arrays.asList() may throw// a ClassCastException (issue 209).  Do the work manually// Curse primitives! :) (JGB)int size = Array.getLength(value);List<Object> answer = new ArrayList<Object>();for (int i = 0; i < size; i++) {Object o = Array.get(value, i);answer.add(o);}return answer;}if (value instanceof Map) {return ((Map) value).entrySet();}

设置了断点,跳到了ForEachSqlNode这个类,其中贴出的部分源码,就是动态替换集合的内容了,其中int uniqueNumber = context.getUniqueNumber();就是可以解释同一个集合对象,多次使用不生效的原因。因为同一个对象,一旦遍历之后它的偏移量不会重置,类似于只执行一次。 

public boolean apply(DynamicContext context) {Map<String, Object> bindings = context.getBindings();final Iterable<?> iterable = evaluator.evaluateIterable(collectionExpression, bindings);boolean first = true;applyOpen(context);int i = 0;for (Object o : iterable) {DynamicContext oldContext = context;if (first) {context = new PrefixedContext(context, "");} else {if (separator != null) {context = new PrefixedContext(context, separator);} else {context = new PrefixedContext(context, "");}}int uniqueNumber = context.getUniqueNumber();if (o instanceof Map.Entry) { // Issue #709 @SuppressWarnings("unchecked") Map.Entry<Object, Object> mapEntry = (Map.Entry<Object, Object>) o;applyIndex(context, mapEntry.getKey(), uniqueNumber);applyItem(context, mapEntry.getValue(), uniqueNumber);} else {applyIndex(context, i, uniqueNumber);applyItem(context, o, uniqueNumber);}contents.apply(new FilteredDynamicContext(configuration, context, index, item, uniqueNumber));if (first) first = !((PrefixedContext) context).isPrefixApplied();context = oldContext;i++;}applyClose(context);return true;}

解决方法:

根据阅读源码得出的这个结论,解决思路也很清晰了,就是再定义一个变量就可以了,变量的内容跟第一个变量内容保持一致即可。just do it。

吭哧吭哧,验证正确,打完收工。最后的SQL类似于这样,myList跟myList2内容一样

select id,name from A
where
name in
<foreach item="item" collection="myList" separator="," open="(" close=")" index="">#{item}
</foreach>unionselect id,name from B
where
name in
<foreach item="item2" collection="myList2" separator="," open="(" close=")" index="">#{item2}
</foreach>

 

 

 

 

这篇关于mybatis中foreach重复使用一个对象的问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/471790

相关文章

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束

mybatis中resultMap的association及collectio的使用详解

《mybatis中resultMap的association及collectio的使用详解》MyBatis的resultMap定义数据库结果到Java对象的映射规则,包含id、type等属性,子元素需... 目录1.reusltmap的说明2.association的使用3.collection的使用4.总

mybatis-plus QueryWrapper中or,and的使用及说明

《mybatis-plusQueryWrapper中or,and的使用及说明》使用MyBatisPlusQueryWrapper时,因同时添加角色权限固定条件和多字段模糊查询导致数据异常展示,排查发... 目录QueryWrapper中or,and使用列表中还要同时模糊查询多个字段经过排查这就导致只要whe

SpringBoot集成MyBatis实现SQL拦截器的实战指南

《SpringBoot集成MyBatis实现SQL拦截器的实战指南》这篇文章主要为大家详细介绍了SpringBoot集成MyBatis实现SQL拦截器的相关知识,文中的示例代码讲解详细,有需要的小伙伴... 目录一、为什么需要SQL拦截器?二、MyBATis拦截器基础2.1 核心接口:Interceptor

Python错误AttributeError: 'NoneType' object has no attribute问题的彻底解决方法

《Python错误AttributeError:NoneTypeobjecthasnoattribute问题的彻底解决方法》在Python项目开发和调试过程中,经常会碰到这样一个异常信息... 目录问题背景与概述错误解读:AttributeError: 'NoneType' object has no at

Spring的RedisTemplate的json反序列泛型丢失问题解决

《Spring的RedisTemplate的json反序列泛型丢失问题解决》本文主要介绍了SpringRedisTemplate中使用JSON序列化时泛型信息丢失的问题及其提出三种解决方案,可以根据性... 目录背景解决方案方案一方案二方案三总结背景在使用RedisTemplate操作redis时我们针对

Kotlin Map映射转换问题小结

《KotlinMap映射转换问题小结》文章介绍了Kotlin集合转换的多种方法,包括map(一对一转换)、mapIndexed(带索引)、mapNotNull(过滤null)、mapKeys/map... 目录Kotlin 集合转换:map、mapIndexed、mapNotNull、mapKeys、map

nginx中端口无权限的问题解决

《nginx中端口无权限的问题解决》当Nginx日志报错bind()to80failed(13:Permissiondenied)时,这通常是由于权限不足导致Nginx无法绑定到80端口,下面就来... 目录一、问题原因分析二、解决方案1. 以 root 权限运行 Nginx(不推荐)2. 为 Nginx

解决1093 - You can‘t specify target table报错问题及原因分析

《解决1093-Youcan‘tspecifytargettable报错问题及原因分析》MySQL1093错误因UPDATE/DELETE语句的FROM子句直接引用目标表或嵌套子查询导致,... 目录报js错原因分析具体原因解决办法方法一:使用临时表方法二:使用JOIN方法三:使用EXISTS示例总结报错原

Windows环境下解决Matplotlib中文字体显示问题的详细教程

《Windows环境下解决Matplotlib中文字体显示问题的详细教程》本文详细介绍了在Windows下解决Matplotlib中文显示问题的方法,包括安装字体、更新缓存、配置文件设置及编码調整,并... 目录引言问题分析解决方案详解1. 检查系统已安装字体2. 手动添加中文字体(以SimHei为例)步骤