【接口报错】从数据类型 varchar 转换为 numeric 时出错

在移动端调用后台接口查询数据时,遇到数据库查询错误,原因是数据更新过程中未使用事务控制,导致查询到空数据并在转换数据类型时出错。通过在业务逻辑层添加异常捕获并抛出自定义异常解决了问题。建议改进更新逻辑,采用事务处理以确保查询一致性。

项目场景:

记录一次后台接口开发中遇到的问题

1、在移动端跳转H5页面请求后台接口
2、开发环境不报错
3、接口是一个查询接口,其中的数据每十分钟更新一次,更新逻辑是先删除表里面的数据,再进行数据统计,最后新增到表里
4、每十分钟结束时,会进行更新操作,操作窗口时间约5-10秒,这段时间内进行查询时,页面报错


问题描述

开发环境不报错,正常运行,但部署到生产环境时出现大串代码提示错误

数据查询过程中会报数据库查询错误

Cause:com.microsoft.sglserveridbc.SQLServerException: 从数据类型 varchar 转换为 numeric 时出错

在这里插入图片描述

APP 中接收数据代码:

    @Override
    public ParkingLotExceptionsVO selectExceptions(@Validated TimeInput ti) {
        return parkingLotMapper.selectExceptions(ti);
    }

数据库查询语句是

    <select id="selectTrafficFlow"
            resultType="com.chngalaxy.wholemarketing.domain.model.parkingLot.TrafficFlowVO">
        SELECT tmp.zcll                trafficFlowTotal,
               tmp.rcclbq              trafficFlowEnter,
               (CASE
                    WHEN tmp.rcclbq = '0' AND tmp.rcclsq = '0' THEN CONCAT('环比', 0, '%')
                    WHEN tmp.rcclbq != '0' AND tmp.rcclsq = '0' THEN CONCAT('环比',
                                                                            CONVERT(DECIMAL(20, 2), CONVERT(DECIMAL(20, 2), tmp.rcclbq)) *
                                                                            100)
                    WHEN (tmp.rcclbq = '0' AND tmp.rcclsq != '0') OR (tmp.rcclbq != '0' AND tmp.rcclsq != '0') THEN CONCAT(
                            '环比', CONVERT(DECIMAL(20, 2), (
                                    (CONVERT(DECIMAL(20, 2), tmp.rcclbq) - CONVERT(DECIMAL(20, 2), tmp.rcclsq)) /
                                    CONVERT(DECIMAL(20, 2), tmp.rcclsq))) * 100, '%')
                    ELSE '' END
                   )                AS trafficFlowEnterChain,
               tmp.ccclbq              trafficFlowExit,
               (CASE
                       WHEN tmp.ccclbq = '0' AND tmp.ccclsq = '0' THEN CONCAT('环比', 0, '%')
                       WHEN tmp.ccclbq != '0' AND tmp.ccclsq = '0' THEN CONCAT('环比',
                                                                               CONVERT(DECIMAL(20, 2), CONVERT(DECIMAL(20, 2), tmp.ccclbq)) *
                                                                               100)
                       WHEN (tmp.ccclbq = '0' AND tmp.ccclsq != '0') OR (tmp.ccclbq != '0' AND tmp.ccclsq != '0') THEN CONCAT(
                               '环比', CONVERT(DECIMAL(20, 2), (
                                       (CONVERT(DECIMAL(20, 2), tmp.ccclbq) - CONVERT(DECIMAL(20, 2), tmp.ccclsq)) /
                                       CONVERT(DECIMAL(20, 2), tmp.ccclsq))) * 100, '%')
                       ELSE '' END) AS trafficFlowExitChain
        FROM (SELECT MAX(IIF(t.id = 1, t.num, '')) zcll,
                     MAX(IIF(t.id = 2, t.num, '')) rcclbq,
                     MAX(IIF(t.id = 3, t.num, '')) rcclsq,
                     MAX(IIF(t.id = 4, t.num, '')) ccclbq,
                     MAX(IIF(t.id = 5, t.num, '')) ccclsq
              FROM bi_tc_rate t
              WHERE t.id IN (1, 2, 3, 4, 5)
                AND SUBSTRING(month, 1, 4) = #{year}
                AND SUBSTRING(month, 5, 2) = #{month}) tmp
    </select>

原因分析:

经测试后发现每次报错是处于更新到窗口时间,在这段时间进行查询时,由于当前查询条件没有筛选到数据(比如2023年3月查询,查询出来的数据已经被删除,正在等待更新中)

由于更新逻辑没有进行事务控制处理,查出来的数据为空,空的数据后来又进行了一次从数据类型 varchar 转换为 numeric 的格式转换,所以前端会返回SQL转换的错误信息


解决方案:

将业务逻辑层的接口查询语句进行try-catch自定义异常捕获,若查询不到当前数据,这直接抛出自定义异常信息

逻辑层代码如下:

    @Override
    public ParkingLotExceptionsVO selectExceptions(@Validated TimeInput ti) {

        ParkingLotExceptionsVO vo;
        try {
            vo = parkingLotMapper.selectExceptions(ti);
        } catch (Exception e) {
            throw new BusinessException(ExceptionCode.PARKING_LOT_ERROR, "数据同步中,请刷新重试");
        }
        return vo;
    }

问题解决后的效果展示:
在这里插入图片描述

顺便如果以后再次遇到这样的场景,需要将数据更新的方式进行事务处理,在更新的窗口时间内进行查询也不会报错,或者先将数据进行统计,再进行删除和新增行数据

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值