mybatis查询结果List<Map<String,Object>>应对动态改变字段类型导致转换结果乱码的问题...

本文深入探讨了在数据库操作中遇到的字段类型变更问题,特别是当尝试将VARCHAR类型字段改为NUMBER类型时,可能会导致乱码现象。通过引入STATEMENT类型的SQL语句和使用${...}

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题场景:

查询语句是select * from 某视图...(备注,此处我们为什么不select具体字段,因为我们是为了动态查询字段,方便实施根据不同客户需求增加、修改字段类型和值、删除字段等场景)。

视图中有属性field1,类型是varchar

结果

field1="字符串类型"

变更field1为number类型

结果

field1="◆~··◆"

乱码。

------------------

解决方案:
在select 标签上加上 statementType="STATEMENT",且在select 语句中不能出现#{...}占位符,如需实现动态SQL效果,可以使用${...}变量,它在运行期会转换为具体的变量值。
原理:
默认statementType是PREPARED,由于PREPARED是默认编译一次,所以你的类型也就固定了,STATEMENT则是每次都编译,另外STATEMENT不支持动态SQL,所以不能出现#{...}占位符。
缺点:
性能降低
后记:
其实这个问题主要是JDBC对SQL预编译知识的理解,其实跟MYBATIS关系不大。所以一般人遇到这个问题,可能首先想到的是如何从MYBATIS来解决,所以相对来说这个问题虽然不难,但较不常见,因为这个需求场景也确实比较变态。
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})}) @Component public class CharacterSetInterceptor implements Interceptor { private static Logger logger = LoggerFactory.getLogger(CharacterSetInterceptor.class); private static final Charset SOURCE_CHARSET = StandardCharsets.ISO_8859_1; private static final Charset TARGET_CHARSET = StandardCharsets.UTF_8; @Override public Object intercept(Invocation invocation) throws Throwable { // Proceed with the original method List<Object> resultList = (List<Object>) invocation.proceed(); // Iterate over each result object in the list for (int i = 0; i < resultList.size(); i++) { Object item = resultList.get(i); // Convert string fields of the object if it's not a Map if (!(item instanceof Map)) { convertStringFields(item); } } return resultList; } private void convertStringFields(Object obj) throws IllegalAccessException { if (obj == null) { return; } Class<?> clazz = obj.getClass(); for (java.lang.reflect.Field field : clazz.getDeclaredFields()) { field.setAccessible(true); Object value = field.get(obj); // Convert string values from SOURCE_CHARSET to TARGET_CHARSET if (value instanceof String) { byte[] sourceBytes = ((String) value).getBytes(SOURCE_CHARSET); String convertedValue = new String(sourceBytes, TARGET_CHARSET); field.set(obj, convertedValue); } else if (value instanceof List) { // Handle lists of objects recursively @SuppressWarnings("unchecked") List<Object> list = (List<Object>) value; for (Object element : list) { convertStringFields(element); } } 代码优化补充完整
最新发布
03-12
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值