pl / sql如何使用带有游标的for循环进行更新操作

Posted

技术标签:

【中文标题】pl / sql如何使用带有游标的for循环进行更新操作【英文标题】:pl/sql How to use for loop with cursor for update operation 【发布时间】:2015-07-01 21:35:27 【问题描述】:

我是 PL/SQL 的新手,在一本书中我发现了这个关于更新游标的示例


    declare
      cursor c_grade(i_student_id in enrollment.student_id%type,
        i_section_id in enrollment.section_id%type
      ) is
        select FINAL_GRADE
          from enrollment
        where student_id_id = i_student_id
        and section_id = i_section_id
        for update;

       cursor c_enrollment is
        select e.student_id, e.section_id
        from enrollment enr, section sec
        where sec.course_no = 135 and
        enr.section_id = sec_section_id;
    begin
      for r_enroll in c_enrollment loop
        for r_grade in c_grade(r_enroll.student_id. r_enroll.section_id) loop
          update enrollment 
          set final_grade = 90
          where student_id = r_enroll.student_id
          and section_id = r_enroll.section_id;      
        end loop;
      end loop;
    end;

我的问题是为什么我需要在这个例子中使用 for update 游标?与此相比有什么好处:

      for r_enroll in c_enrollment loop

          update enrollment 
          set final_grade = 90
          where student_id = r_enroll.student_id
          and section_id = r_enroll.section_id;      

      end loop;

【问题讨论】:

for update lock(protect) rows and other transaction can't change the same rows 【参考方案1】:

正如评论中提到的,FOR UPDATE 子句用于锁定 SELECT 语句中的行,这样在锁定之前没有其他用户能够更改这些行(更新、删除等)释放。

一旦您发出 COMMIT 或 ROLLBACK 语句,锁通常会自动释放。当有大量 DML 语句在来自不同用户的同一组数据上运行时,这特别有用。例如,您需要在某个时刻更新 ID 最高的行,但在更新该行之前,另一行已被不同的用户更新为 ID 较高的行。

对于您的示例,使用

for r_grade in c_grade(r_enroll.student_id. r_enroll.section_id) loop

保证你更新的是你锁定的版本,在你之前没有其他人更新过。

您可以通过示例here找到详细说明

【讨论】:

【参考方案2】:

为了详细说明您的问题,Oracle 中有两种类型的锁定机制

    1) Pessimistic Locking
    2) Optimistic Locking

    Optimistic locking is generally implemented by developers in the code some timestamp etc phenomena so that at one time only one user at a time can update a particular record.

    Pessimistic locking on the other hand (what you have used in the question) is the inbuilt functionality your database is providing to handle locking mechanism automatically.

Let me know if this clears your doubt on this.

【讨论】:

以上是关于pl / sql如何使用带有游标的for循环进行更新操作的主要内容,如果未能解决你的问题,请参考以下文章

使用 FETCH 的 PL/SQL 游标 FOR 循环

如何在 PL/SQL 代码的 for 循环中创建游标并将结果批量收集到表中

为啥我们不需要在 pl sql 的 for 循环中打开和获取显式游标?

带有游标参数 (LOOP FETCH) 和 For 循环子查询的 PL/SQL 查询出错

PL/SQL控制语句(循环控制语句)

如何将游标添加到 PL/SQL 块中的过程中?