首页 > 数据库 >Clob转String报错SQLRecoverableException: 关闭的连接

Clob转String报错SQLRecoverableException: 关闭的连接

时间:2025-01-10 11:56:46浏览次数:1  
标签:map Convert java String Clob convert hutool 报错 clazz

背景

接到任务需要做一个数据上传的功能,主要是从20多个视图中查询数据,然后调用接口上传数据。

经过

我把这个功能分成两部分:数据查询、数据上传。

上传数据的接口只有一个,通过指定一个参数来区分不同类型的数据,而查询数据的视图中的数据不需要我们处理,因此决定查询数据时使用map来接收参数。

这么做的原因有几个:

  1. 视图字段与接口参数不完全匹配,有的少了几个字段
  2. 接口参数名是驼峰命名,视图也是驼峰命名但因为是Oracle数据库不区分大小写所以实际是大写
  3. 不能通过SQL写下划线别名,因为添加下划线后别名长度会超过30

因此,我决定直接使用SELECT *查询数据,使用List<Map<String,Object>>来接收数据。

但是还有个问题,接口中有部分数据是存在对象嵌套的,部分字段是List类型。

List类型的数据不是通过关联查询得到的,而是需要另外写一个查询去查。

考虑到以上,我决定mapper层查询数据使用map来接收,然后在service层先查询数据再转换成对象。

数据查询编写了一个DataQueryMapperDataQueryService:

public interface DataQueryMapper {
    List<Map<String, Object>> getPage(@Param("req") PatientReq req);
}
@Service
@RequiredArgsConstructor
public class DataQueryService implements IDataQueryService {
    
    private final DataQueryMapper baseMapper;
    
    @Override
    public List<PageData> getPage(PatientReq req) {
        return NcBeanUtil.mapToBean(baseMapper.getPage(req), PageData.class);
    }
}

BeanUtil用于转换对象:

public class NcBeanUtil {

    private static final Map<Class<?>, Map<String, Field>> CACHE = new HashMap<>();

    private NcBeanUtil() {

    }

    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {
        if (CollUtil.isEmpty(map)) {
            return null;
        }
        Map<String, Field> fieldMap = getFieldMap(clazz);
        T instance = ReflectUtil.newInstance(clazz);
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            Field field = fieldMap.get(key);
            if (field == null) {
                continue;
            }
            Class<?> fieldType = field.getType();
            Object fieldValue = Convert.convert(fieldType, value);
            ReflectUtil.setFieldValue(instance, field, fieldValue);
        }
        return instance;
    }

    public static <T> List<T> mapToBean(List<Map<String, Object>> mapList, Class<T> clazz) {
        if (CollUtil.isEmpty(mapList)) {
            return Collections.emptyList();
        }
        return mapList.stream().map(map -> NcBeanUtil.mapToBean(map, clazz)).collect(Collectors.toList());
    }

    private static <T> Map<String, Field> getFieldMap(Class<T> clazz) {
        if (CACHE.containsKey(clazz)) {
            return CACHE.get(clazz);
        }
        Map<String, Field> fieldMap = new HashMap<>();
        Field[] fields = ReflectUtil.getFields(clazz);
        for (Field field : fields) {
            String name = field.getName();
            String key = name.toUpperCase(Locale.ROOT);
            fieldMap.put(key, field);
        }
        CACHE.put(clazz, fieldMap);
        return fieldMap;
    }

}

很巧妙的先使用Bean的field定义转换成大写,与原先的field映射存入map,转换时使用map获取到实际的field并填充转换后的值。

报错

运行以后,效果很好,只是在查询其中几个视图时出现了报错:

SQLRecoverableException: 关闭的连接
cn.hutool.core.convert.ConvertException: SQLRecoverableException: 关闭的连接
	at cn.hutool.core.convert.impl.StringConverter.clobToStr(StringConverter.java:56)
	at cn.hutool.core.convert.impl.StringConverter.convertInternal(StringConverter.java:32)
	at cn.hutool.core.convert.impl.StringConverter.convertInternal(StringConverter.java:22)
	at cn.hutool.core.convert.AbstractConverter.convert(AbstractConverter.java:58)
	at cn.hutool.core.convert.ConverterRegistry.convert(ConverterRegistry.java:207)
	at cn.hutool.core.convert.ConverterRegistry.convert(ConverterRegistry.java:247)
	at cn.hutool.core.convert.Convert.convertWithCheck(Convert.java:753)
	at cn.hutool.core.convert.Convert.convert(Convert.java:706)
	at cn.hutool.core.convert.Convert.convert(Convert.java:677)
	at cn.hutool.core.convert.Convert.convert(Convert.java:651)
	at ...mapToBean(NcBeanUtil.java:36)
	...
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
	at ...NcBeanUtil.mapToBean(NcBeanUtil.java:50)
	...

奇怪的现象发生了,为什么在mapToBean的时候会发生SQL相关的异常?

顺着堆栈,发现是NcBeanUtil在使用hutool转换时发生异常

public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {
    ...
    Object fieldValue = Convert.convert(fieldType, value);
    ...
}

解决

百思不得其解,这种报错也是第一次见,为什么连接会关闭?

上网查询一番,发现都是说数据库连接断开之类的,但是重复实验很多次,只有特定几个查询会发生这种异常。

于是在转换时添加了日志,查看是什么原因导致的

public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {
   ...
        try {
            Object fieldValue = Convert.convert(fieldType, value);
            ReflectUtil.setFieldValue(instance, field, fieldValue);
        } catch (Exception e) {
            log.error("Convert异常: {}:{} valueType = {}, fieldType = {}", key, value, value == null ? null : value.getClass(), fieldType);
            throw e;
        }
    ...
}

结果出来了

Convert异常: NCMARITALHISTORY:oracle.sql.CLOB@6bc2903b valueType = class oracle.sql.CLOB, fieldType = class java.lang.String

valueType是Clob,fieldType是String,异常是在Clob转String时发生的。

private static String clobToStr(Clob clob) {
    Reader reader = null;
    try {
        reader = clob.getCharacterStream();
        return IoUtil.read(reader);
    } catch (SQLException e) {
        throw new ConvertException(e);
    } finally {
        IoUtil.close(reader);
    }
}

继续在网络上检索,看到有这样一个说法

oracle-解析CLOB格式字段转String

SQL CLOB是 内置类型,它将字符大对象(Character Large Object) 存储为数据库表某一行中的一个列值。默认情况下,驱动程序使用 SQL locator(CLOB)实现 Clob 对象,这意味着 CLOB 对象包含一个指向 SQL CLOB 数据的逻辑指针而不是数据本身。Clob 对象在它被创建的事务处理期间有效。

Clob 对象在它被创建的事务处理期间有效

莫非是查询后连接关闭或者没有开启事务,连接先关闭了再把Clob转String导致报错?

尝试添加了@Transaction注解

@Override
@Transactional(rollbackFor = Exception.class)
public List<PageData> get=Page(PatientReq req) {
    return NcBeanUtil.mapToBean(baseMapper.getPage(req), PageData.class);
}

没想到轻松解决了。

标签:map,Convert,java,String,Clob,convert,hutool,报错,clazz
From: https://www.cnblogs.com/montaro/p/18663710

相关文章

  • 【YashanDB知识库】kettle做增量同步,出现报错:Unrecognized VM option 'MaxPermSize-25
    本文内容来自YashanDB官网,原文内容请见https://www.yashandb.com/newsinfo/7863039.html?templateId=1718516问题现象kettle在增量同步过程,出现报错:UnrecognizedVMoption'MaxPermSize=256m'问题的风险及影响无法使用kettle做增量同步,导致迁移进度会有所影响问题影响的版......
  • shell中$后加引号有什么用($"string"和$'string')
    (1).如果没有特殊定制bash环境或有特殊需求,$"string"和"string"是完全等价的,使用$""只是为了保证本地化。以下是manbash关于$""的解释:Adouble-quotedstringprecededbyadollarsign($"string")willcausethestringtobetranslatedaccordi......
  • NRF24L01模块STM32-调试心得:报错 1E
    前言环境:芯片:STM32F103C8T6Keil:V5.24.2.0调试时我们会尝试读取STATUS寄存器状态来了解模块目前的状态,但是我们在读取时至为0x1E,这就很纳闷,根据寄存器描述0x1E:对应寄存器4:1,关系有:达到最大重发次数        RXFIFO为空,第四位很好理解也......
  • 【YashanDB知识库】解决mybatis的mapper文件sql语句结尾加分号";"报错
    本文内容来自YashanDB官网,原文内容请见https://www.yashandb.com/newsinfo/7863046.html?templateId=1718516现象mybatis或mybaits-plus的mapper文件sql结尾加分号";"执行时报错:”YAS-04209unexpectedword;“解决办法将sql结尾分号“;”去掉。使用注解方式写的sql语句也......
  • Oracle SQL优化过程一则以及group by少见用法报错点
     OracleSQL优化过程一则以及groupby少见用法报错点 业务让帮忙优化一条sql,sql文本如下(脱敏):selectto_char(t.create_time,'yyyy-mm')月份,count(*)总数,(selectcount(v.seq_no)fromzkm.testvwhereto_char(v.create_time,......
  • linux下启动第二个RocketMQ,报错java.lang.RuntimeException: Lock failed,MQ already
    报错如下图: 这种情况下启动两个broker,基本都会在第二个broker,报lockfailed,MQalreadystarted因为使用了相同的默认配置(只启动一个broker不受影响) 不同的配置,需求满足最基本的配置不同brokerName不同brokerId不同listenPort不同storePathRootDir......
  • StringBuilder练习项目代码及相关知识点
    1.动态字符串操作需求:编写一个程序,接收用户输入的多个单词,并将它们组合成一个完整的句子,同时支持以下功能:动态添加单词删除某些单词将句子反转importjava.util.Scanner;publicclassStringBuilderDemo{publicstaticvoidmain(String[]args){StringB......
  • Java进阶__String类
    在Java中,String类用于表示一串字符序列。String是一个对象类,又被设计为不可变类(immutableclass)。String类在Java中提供了多种处理字符串的方法,还对性能进行了优化。1.特点不可变性:String对象是不可变的,意味着一旦一个String对象被创建,它的值不能被更改(在string类里......
  • 【Azure Function】部署Java Function失败:报错deploy [ERROR] Status code 401和警告
    问题描述部署JavaFunctionApp到中国区Azure上时,遇见了错误信息:错误信息:deploy[ERROR]Statuscode401,(emptybody)警告信息:ChinaNorth3maynotbeavalidregion,pleaserefertohttps://aka.ms/maven_function_configuration#supported-regionsforvalues. ......
  • docker拉取报错/docker切换国内镜像源
    报错场景:docker从远程拉取镜像是出现的报错问题描述报错内容为Errorresponsefromdaemon:Get"https://registry-1.docker.io/v2/":net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders原因分析:国内dock......