逐行处理数据时避免死循环

如何避免 QT 的 View/Model 模式产生消息激活的死循环? 当收到QTableWidget的itemChanged信号时,关联的槽函数一般用于响应单元格数据的修改。 阅读详情

当在一个循环体内逐行处理数据时,你必须确保该循环不会无休止的执行下去。在此,我将描述三个死循环的场景。已经有很多论文论及循环和基于集合的解决方式之间可行性的优劣,这些讨论我就不再赘述。这里我们假定你必须使用某种循环。

 还要说明一点:我在此举例说明有些情况下可能会出现死循环,而且尽可能的举出最简单的例子。在这些场景中,我并没有说明循环的方法优于基于集合的解决方法,所以请不要对我所举出的简短例子作如此理解。

 使用SET和SELECT都可能变量赋值失败

 请读者自行分析,下面的例子就证明了这两种情况:

DECLARE @i1 INT, @i2 INT, @i3 INT;

SELECT @i1=-1, @i2=-1, @i3=-1;

PRINT 'the following SELECT will not change the value of @i1'

PRINT 'because the result set is empty'

SELECT @i1=1 WHERE 1=2;

SELECT @i1 AS [@i1];

PRINT 'the following SET will change the value of @i2 to NULL'

PRINT 'because the result set is empty'

SET @i2=(SELECT 1 WHERE 1=2);

SELECT @i2 AS [@i2];

PRINT 'the following SELECT will not change the value of @i3'

PRINT 'because it will raise an exception'

SET @i3=(SELECT 1 UNION ALL SELECT 2);

SELECT @i3 AS [@i3];

由于返回空的数据集,下面的SELECT语句将不会改变@i1的值。

@i1

-----------

-1

 

(1 row(s) affected)

 

由于返回空的数据集,下面的SET语句将不会改变@i2的值。

@i2

-----------

NULL

 

(1 row(s) affected)

 

由于产生以异常(返回多行记录),下面的SELECT语句将不会改变@i3的值。

Msg 512, Level 16, State 1, Line 13

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

@i3

-----------

-1

 

(1 row(s) affected)

这是预期的结果,但你必须意识到这一点,否则你的循环可能无休止的执行下去。

Make sure you have read Tony Rogerson's post on the topic.

确保你已经阅读了Tony Rogerson关于此主题的论文。

 当SELECT语句改变变量值失败时,可能导致死循环

请看下列表、样例数据和存储过程:

CREATE TABLE [data].[Orders](

      [OrderID] [int] NOT NULL,

      [OrderDate] [datetime] NOT NULL,

      IsProcessed CHAR(1) NOT NULL,

 CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED

(

      [OrderID] ASC

)WITH (IGNORE_DUP_KEY = OFF)

)

GO

DELETE FROM [data].[Orders];

INSERT [data].[Orders](

      [OrderID],

      [OrderDate],

      IsProcessed)

SELECT 1, '20090420', 'N' UNION ALL

SELECT 2, '20090421', 'N' UNION ALL

SELECT 3, '20090422', 'N';

CREATE PROCEDURE dbo.ProcessNOrders

  @IDsIntervalSize INT

AS

DECLARE @minID INT, @ID INT;

SELECT @minID=MIN([OrderID]), @ID=MIN([OrderID]) FROM [data].[Orders];

WHILE @ID<(@minID+@IDsIntervalSize) BEGIN

  UPDATE [data].[Orders]

    SET IsProcessed='Y'

    WHERE [OrderID] = @ID;

  SELECT TOP 1 @ID=[OrderID]

    FROM [data].[Orders]

    WHERE IsProcessed='N'

    ORDER BY [OrderID];

  PRINT @ID;

END;

-- 本次调用成功

EXEC dbo.ProcessNOrders 2;

GO

 

-- 恢复数据

UPDATE [data].[Orders]

  SET IsProcessed='N';

GO

 

-- 本次调用处理了3条orders数据后陷入死循环

-- 取消执行

EXEC dbo.ProcessNOrders 10;

解决办法很简单,如下所示——只要确保赋值前变量值被改变

ALTER PROCEDURE dbo.ProcessNOrders

  @IDsIntervalSize INT

AS

DECLARE @minID INT, @ID INT;

SELECT @minID=MIN([OrderID]), @ID=MIN([OrderID]) FROM [data].[Orders];

WHILE @ID<(@minID+@IDsIntervalSize) BEGIN

  UPDATE [data].[Orders]

    SET IsProcessed='Y'

    WHERE [OrderID] = @ID;

  SET @ID = NULL;

  SELECT TOP 1 @ID=[OrderID]

    FROM [data].[Orders]

    WHERE IsProcessed='N'

    ORDER BY [OrderID];

  PRINT @ID;

END;

GO

UPDATE [data].[Orders]

  SET IsProcessed='N';

GO

 

-- 本次调用处理了3条orders数据后完成处理

 

EXEC dbo.ProcessNOrders 10;

 

你也可以使用SET替换SELECT,那样也可以解决这个问题:

 

ALTER PROCEDURE dbo.ProcessNOrders

  @IDsIntervalSize INT

AS

DECLARE @minID INT, @ID INT;

SELECT @minID=MIN([OrderID]), @ID=MIN([OrderID]) FROM [data].[Orders];

WHILE @ID<(@minID+@IDsIntervalSize) BEGIN

  UPDATE [data].[Orders]

    SET IsProcessed='Y'

    WHERE [OrderID] = @ID;

  SET @ID = (

        SELECT TOP 1 [OrderID]

            FROM [data].[Orders]

            WHERE IsProcessed='N'

            ORDER BY [OrderID]);

  PRINT @ID;

END;

 

当赋值产生异常而导致对变量值的改变失败时

创建如下对象:

CREATE VIEW dbo.LongestWaitingNotProcessedOrder

AS

SELECT

      [OrderID],

      [OrderDate],

      IsProcessed

FROM [data].[Orders]

WHERE [OrderDate] = (SELECT MIN([OrderDate]) FROM [data].[Orders] WHERE IsProcessed='N')

AND IsProcessed='N'

GO

CREATE PROCEDURE dbo.ProcessOrder @OrderID SMALLINT

AS

SET NOCOUNT ON;

UPDATE [data].[Orders] SET IsProcessed='Y'

  WHERE [OrderID]=@OrderID;

RETURN @@ERROR;

GO

 

当未处理的order中没有相同的order date时,下面的循环会正确执行。

UPDATE [data].[Orders]

  SET IsProcessed='N';

 

DECLARE @ID INT;

SET @ID=-1;

WHILE @ID IS NOT NULL BEGIN

  SET @ID=(SELECT [OrderID]

    FROM dbo.LongestWaitingNotProcessedOrder);

  PRINT @ID;

  EXEC dbo.ProcessOrder @OrderID=@ID;

END

 

当orders中存在两条相同order date的未处理记录时,对变量值的赋值过程(改变变量值)会失败,从而导致死循环。运行这个脚本后回到上面的循环语句,你会发现该循环变成了死循环。

 

UPDATE [data].[Orders]

  SET IsProcessed='N';

INSERT [data].[Orders](

      [OrderID],

      [OrderDate],

      IsProcessed)

SELECT 4, '20090421', 'N';

 

同样,解决起来很简单。你只需把循环嵌入TRY…CATCH块中,如下所示:

 

DECLARE @ID INT;

SET @ID=-1;

BEGIN TRY

      WHILE @ID IS NOT NULL BEGIN

        SET @ID=(SELECT [OrderID]

            FROM dbo.LongestWaitingNotProcessedOrder);

        PRINT @ID;

        EXEC dbo.ProcessOrder @OrderID=@ID;

      END

END TRY BEGIN CATCH

  SELECT ERROR_NUMBER(), ERROR_MESSAGE();

END CATCH

现在循环会在第一次出现异常后结束执行。然而,如果存储过程处理一笔order失败,你仍可能陷入死循环。

重新考虑基于集合的解决方法

你可以看出,在Transact SQL中开发健壮的循环是相当复杂的,其中确有一些技巧。你也许可以重新考虑使用基于集合的解决方式来替换循环方法。

使用表变量 

下面的方法也相当健壮:

DECLARE @orderIDs TABLE(n INT, ID INT);

INSERT INTO @orderIDs(n, ID)

SELECT ROW_NUMBER() OVER(ORDER BY [OrderDate]), [OrderID]

  FROM [data].[Orders] WHERE IsProcessed='N';

DECLARE @ID INT, @n INT, @MaxN INT;

SELECT @n=1, @MaxN = MAX(n) FROM @orderIDs;

WHILE @n <= @MaxN BEGIN

  SELECT @ID = ID FROM @orderIDs WHERE n=@n;

  PRINT @ID;

  EXEC dbo.ProcessOrder @OrderID=@ID;

  SET @n=@n+1;

END

即使存储过程处理一笔order时可能会失败,循环仍然能够完成,因为每笔order将只被处理一次。

C语言由scanf(“%d“,)非法输入字符造成的死循环及其解决方案 声明:此文章仅作为C语言学习历程中的思路整理,用于解决入门阶段较为浅显的问题,如有错误还请指正。 现象描述: 代码要求实现用户输入1或2,通过scanf("%d",&a)读取这个值,从而判断分属于1或2的两种情况。输入非1,2的数字都应该返回"Invalid Number!",并且要求重新输入数字。 while(a!=1&&a!=2) { printf("Invalid Number!\n"); printf("Enter the number:"); scan 阅读详情

相关推荐

php死循环处理大数据(千张表,上亿级别数据)

几个重点, 1,文本记录数据落地点,2,死循环断开点  3,防止sql断开连接(MySQL server has gone away)4,防止php超时  5,日志跟踪   6,递归处理数据(业务需求),7,正则匹配数据(业务需求)增强程序的可执行性 &lt;?php /** * Created by PhpStorm. * User: Administrator * Date: 2...

Baron0071的博客 2386

逐行处理数据时避免死循环--避免死循环2

逐行处理数据时避免死循环Alexander Kuznetsovhttp://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/04/23/when-you-process-your-rows-one-by-one-avoid-infinite-loops.aspx 当在一个循环体内逐行处理数据时,你必须确保该循环不会无休止的执行下

GRANDTREE的专栏 1608

用STC8单片机解码EV1527遥控信号:从波形分析到C代码实现(附完整库)

本文详细介绍了如何使用STC8单片机解码EV1527遥控信号,从波形分析到C代码实现的完整过程。内容包括EV1527协议解析、硬件搭建、信号捕获技巧、解码算法实现及优化策略,并附有完整库代码,帮助开发者快速实现智能家居设备的无线控制。

weixin_34093995的博客 295

危险的死循环:条件恒为真

死循环指的是,在程序中定义的循环控制条件一直为真,导致程序在循环过程中无法跳出,不断执行同一段代码,直到程序被手动终止或者发生系统错误。通常来说,如果没有特殊的程序设计来跳出循环,那么程序就会一直执行循环语句,陷入死循环的状态。死循环是一种非常危险的程序状态,对于程序员来说,应当高度重视避免死循环的出现,规范编写代码以确保程序的正确性和稳定性。

weixin_47712251的博客 4749

MLC-LLM框架在安卓设备上的模型编译与部署全流程解析

本文详细解析了如何利用MLC-LLM框架在安卓设备上编译与部署大语言模型。从环境搭建、模型获取与量化编译,到最终的安卓应用打包与调试,提供了完整的实战流程。重点介绍了如何通过MLC-LLM将大型模型优化为适合移动端运行的格式,实现本地、低延迟、隐私安全的AI应用部署。

weixin_29251337的博客 475

Python爬虫实战:如何优雅地处理BOSS直聘的反爬机制与Cookie失效问题

本文详细介绍了如何通过Python爬虫技术优雅应对BOSS直聘的反爬机制与Cookie失效问题。从多账号轮换、动态请求头生成到代理IP管理,提供了一套完整的解决方案,帮助开发者构建稳定高效的数据采集系统,有效提升爬虫成功率与数据质量。

weixin_30733003的博客 1562

【SQL Server insert】关联插入多行数据

关联插入多行数据 因为需要上线项目,有这样一个需求,代码如下: INSERT into A(ID,PID)values((SELECT MAX(ID) FROM A)+1,0) INSERT into A(ID,PID)values((SELECT MAX(ID) FROM A)+1, 第一条数据的ID ) 直接Select查询第一条数据需要增加wehere条件 执行会抛出如下错误 Subquery returned more than 1 value. This is not permitted whe

离离火的博客 2347

【NIFI】实现HANA->ORACLE数据同步

实现 HANA->ORACLE数据同步。

weixin_43159039的博客 1506

sql server中存储过程提示错误

1、今天写存储过程是运行时总是提示如下错误: Subquery returned more than 1 value. This is not permitted when the subquery follows =, t!=, <, <= ,>, >= or when he subquery is used as an expression. ...

weixin_30387423的博客 3208

UE5 推荐的资产命名规范

在开发阶段中,随着 虚幻引擎(UE)(Unreal Engine (UE)) 项目日益复杂,内容浏览器(Content Browser) 中的 资产(Assets) 列表会不断扩充。这会导致资产出现各种变体版本,也会导致资产名称因过于相似而造成混淆。比如,你有一个文件夹名为"Soldier",这个文件夹中有蓝图、纹理和模型,它们的名称中都带"Soldier"一词,但在简单列表中,很难区别它们。

一碗清深的博客 3373

银行统一监管报送系统

依据《银行业金融机构数据治理指引》,银行业金融机构应当建立适应监管数据报送工作需要的信息系统,实现流程控制的程序化,提高监管数据加工的自动化程度。银行业金融机构应当将监管数据纳入数据治理,建立工作机制和流程,确保监管数据报送工作有效组织开展,监管数据质量持续提升。银行通常要对接报送EAST5.0、1104、CRSS等近40个监管应用,涉及近1000张报表。表13-01是主要的监管报送应用、报送依据、报送规范、监管机构名称。

银行信息系统应用架构详解 4348

避免死循环――第一部分

避免死循环――第一部分 Alexander Kuznetsov原文:http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/04/20/avoiding-infinite-loops-part-one.aspx 尽管有很多关于使用游标(cursor)还是循环来获取最好性能的讨论,不过有一点是毫无

GRANDTREE的专栏 1585

QGIS编译(跨平台编译)之五十六:QScintilla编译、QScintilla安装(Windows、Linux、MacOS环境下编译、安装)

QGIS编译;QScintilla编译、QScintilla安装(Windows、Linux、MacOS环境下编译、安装)

LuckyHanMo的博客 1896

一文搞懂如何有效避免死循环

确保循环条件最终会变为False设置安全防护措施(最大迭代次数/超时)谨慎使用循环控制语句优先使用更安全的循环结构(如for循环)添加适当的监控和调试输出通过遵循这些实践原则,可以显著降低死循环风险,编写出更健壮的Python代码。记住:防御性编程是避免循环问题的关键!

m0_74107848的博客 1666

MATLAB船舶开尔文尾迹三维仿真建模

开尔文尾迹介绍 Kelvin最早研究舰船在水面运动在水面上形成波纹的原理,主要针对静水中点源运动的尾迹问题,并给出尾迹的张角和波高分布情况。由 Kelvin 的理论,一般情况下假设由一个理想点源来代替舰船,开尔文尾迹由分歧波和横断波组成,分歧波向船的两侧扩散,而横断波主要向船的后方传播,在相遇的地方两波相干形成尖头波,且尖头波位于尾迹角16°到19.5°之间,又因为尖头波波长过短,以至于无法单独的区分出每个尖头波的波前,所有的波前在视觉效果上就连成一条直线表现为亮线,称为开尔文臂,开尔文臂以船身对称,且角度

qq_19512613的博客 3844

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

小程序 数据监听(observers),避免赋值死循环

在小程序开发过程中,我们通过 observers 监听处理 properties 组件数学列表的过程中,免不了对 当前数据进行处理 在我们对监听的数据进行赋值时候,会造成死循环,其实这个问题在大多数框架中都有这个问题。 小栗子????[错误示范] properties: { playlist: { type: Object } }, // 数据监听 ...

Chad97的博客 3085

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

ARM7异常返回地址自动修正避免ESP32死循环

本文深入分析ESP32在非法内存访问后陷入异常死循环的机制,揭示Xtensa LX6架构与ARM在异常处理上的本质差异,并提出通过修正EPC1寄存器实现系统自救的实战方案,提升嵌入式系统的可靠性和可观测性。

i8j9k0l1的博客 5379

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

c++中如何避免死循环

在C++中,避免死循环的关键是确保循环有一个明确的终止条件。语句或函数来退出循环。同时,要确保代码的异常处理和内存管理正确,以避免潜在的问题。总之,避免死循环的关键是确保循环有一个明确的终止条件,并在适当的时候使用。

2301_79022773的博客 803

RabbitMQ消费端异常进入死循环-处理

RabbitMQ实现消费端异常处理 前言 思考:因为在开发项目时,RabbitMQ的消费端出现了异常(工具类操作文件时,未找到文件路径)。由于在此之前并未对该异常进行预判,导致异常出现后,消费端仍然对MQ的消息进行消费,但是出现异常后无法对MQ进行回复,所以造成后果消费端一直消费该条信息,进入死循环! 从而引发了自己的思考:1. 开发时难免会出现异常,这种异常如果事先未预判,那么在程序运行中,消费端该怎么避免以上出现的死循环;2. 如果事先预判到异常,对其进行了抛出或捕获,消费端又该如何表现? 异常

qq_29766917的博客 8795

[问题记录.pg]使用 WITH RECURSIVE 时遇到问题数据,引发死循环。如何避免?

一个因 WITH RECURSIVE 递归查询导致的死循环,引发应用程序内存和CPU涨爆。改进sql写法,避免该问题。

:: Dotnet Fantasy :: 2386

java 递归死循环_java嵌套事物与递归调用避免死循环问题

总结了一些项目工作中的经验,顺带说一下解决问题的思路,方式倒是有很多种,看实际业务应用场景。递归调用避免死循环问题递归坏处:由于递归需要堆栈,所以内存消耗要比非递归代码要大很多。而且,如果递归深度太大,可能系统撑不住。内存会存在突然飙升的情况。如果是数据错误导致无限循环,那问题就大了。所以这方面问题在开发的时候需要注意。解决办法:1.传递变量进行控制,比如递归50次后就结束调用,直接返回结果,使程...

weixin_42527665的博客 2239

Swiper列表轮播动态获取数据最后一页数据陷入死循环问题

当获取数据时,在下方代码中添加loop:true;autoplay:true;会实现页面的动态循环;让循环的每一页显示6条数据,每次循环6条数据, 但是出现的问题是,当数据的数量少于或者大于的时候,就会出现轮播的时候最后显示的几条数据陷入死循环(无限循环最后几条数据)状态, 而造成这个死循环的原因就是数据的过多或过少,当数据显示的刚好是每一页的倍数是,比如6,数据有12条、18条、24条都不会出现问题,而当数据有15条或者20条的时候就会出现死循环的状态, 目前的解决方案就是需要将数据的数量控制在所需范围之

wind_linjie的博客 1212

springboot 使用hibernate进行双向关联json解析时死循环处理

一.问题当我们进行hibernate进行双向关联时,我们用json解析时进入死循环,如果我们不用json不会死循环因为不用JSON时一般有懒加载不会出现死循环。 例如下面: Examination.java中Examination一对多questions @OneToMany(targetEntity = Question.class, cascade = CascadeType.REM

hanghangde的博客 5884

【Java中三种循环的详解与区别和使用场景|死循环的避免和利用】

Java中三种循环的详解与区别和使用场景|死循环的避免和利用

本人大一,励志后端开发,为了更好的加深记忆并且日后复习方便,此博客是我学习成长记录,与大家分享所学,感谢大佬批评指正 2057

Python流程控制:while循环嵌套与死循环避免技巧

本文深入讲解了Python中while循环嵌套与死循环避免技巧的核心概念和实践方法。主要内容包括:1) while循环嵌套的基本定义和重要性;2) 技术原理详解,包括核心架构和实现方法;3) 实践应用部分提供环境准备和基础/进阶示例;4) 常见问题解决方案,如环境配置和运行时错误处理。文章通过代码示例、表格和流程图等形式,系统性地介绍了这一Python编程核心知识点,帮助开发者掌握循环嵌套的正确使用方式并避免死循环问题,提升代码质量和开发效率。

未来 95% 的 AI 应用将变得隐形,广泛融入日常生活。 7005

解决cin因为输入错误的数据类型进入死循环的问题

cin输入错误,清空缓存的解决方法: 点这里 补充: cin.xx()在个编译器下有不兼容情况,一般情况下推荐使用getchar()手动清空缓存。 cin.clear(): 改变输入的错误标识 cin.clear()默认参数为0,即无错误,正常操作。当我们输入错误时,它的状态标识改为fail,即错误,用cout对用户输出信息,再用cin.clear让错误标识改回为0,让我们可以继续输入...

weixin_43098127的博客 1212
上一篇: 存储过程将.txt.xls文件数据导入数据库表格
下一篇: 数据备份还原中排他锁问题的解决方案
晓梦庄子
博客等级 码龄19年 4粉丝 129原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓梦庄子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值