本文测试在pl/sql编程中,更新游标数据的2种方式以及并发条件下各种方式的实际表现。2种方式的效率问题不在此文讨论之列!

一、环境准备数据库:Oracle10.2.0.4

测试工具:PL/SQL Developer9

二、数据准备我们使用oracle自带的演示用户scott登录数据库,为清楚看到数据变化,执行以下语句:

SQL> update emp t set t.sal=1000;

14 rows updated

SQL> commit;

Commit complete

Emp表的sal字段初始化为1000

查询emp表:

SELECT t.empno, t.ename,t.job, t.sal, ROWID rd from emp t;

结果如图1所示:

图1

Sal字段已经全部更新为1000

三、创建存储过程ps_cursor_for_update

CREATE OR REPLACE PROCEDURE ps_cursor_for_update

(p_sal PLS_INTEGER) IS

CURSOR c IS

SELECT t.empno, t.ename, t.hiredate, ROWID rd

FROM EMP t

WHERE t.sal = 1000

FOR UPDATE;

v_emp_record c%ROWTYPE;

v_rows       PLS_INTEGER := 0;

BEGIN

OPEN c;

LOOP

FETCH c

INTO v_emp_record;

EXIT WHEN c%NOTFOUND;

UPDATE EMP SET sal = p_sal WHERE CURRENT OF c;

v_rows := SQL%ROWCOUNT;

dbms_output.put_line(v_rows);

END LOOP;

COMMIT;

CLOSE c;

END ps_cursor_for_update;

四、测试ps_cursor_for_updatePL/SQL Developer工具具有很强大的plsql调试功能,我们使用两个test窗口进行模拟并发执行的情况

在编辑存储过程的界面,在打开游标的代码行加入一个断点:

图2

在存储过程ps_cursor_for_update上点击右键,打开两个test窗口:

窗口1中,输入参数填写2000

窗口2中,输入参数填写3000,如图3、4所示:

图3

图4

两个窗口分别点击 start bugger按钮,开始调试,并点击run按钮,分别运行到打开游标的一行,并在窗口2中进行单步调试,运行到如图5所示位置:

图5

此时窗口1中,开始单步调试,发现状态栏处于运行中(图7),但调试光标始终停在断点行(图6)

图6

图7

说明游标打开的数据已经被窗口2的进程锁定,所以窗口1的进程无法打开数据

下面把窗口2的断点去掉,并点击run按钮使此过程执行完毕,可以发现,此时窗口1中,代码已经执行到了原断点位置的下一行:

图8

结论:窗口2执行了commit语句,PL/SQL过程结束,并解锁操作的数据,使窗口1的过程得以打开游标。

查询emp表的数据:

图9

发现sal字段已经更新为3000

注意,打开游标的sql条件中,sal字段是1000,所以,继续运行窗口1,完成PL/SQL过程,再次查看emp数据:

图10

发现sql字段还是3000;

结论:由于窗口2锁定了emp数据,并将sal字段更新为3000,使得窗口1在窗口2执行完毕而打开游标时,sal为1000的数据已经不存在了,所以窗口1的PL/SQL过程,没有打开任何数据,也就没有更新任何数据。

由此可知,在打开游标的select语句中,使用for update子句,能在并发条件下有效地保证数据的正确。

五、创建存储过程ps_cursor_no_for_update

CREATE OR REPLACE PROCEDURE ps_cursor_no_for_update(p_sal PLS_INTEGER) IS

CURSOR c IS

SELECT t.empno, t.ename, t.hiredate, ROWID rd

FROM EMP t

WHERE t.sal = 1000;

v_emp_record c%ROWTYPE;

v_rows       PLS_INTEGER := 0;

BEGIN

OPEN c;

LOOP

FETCH c

INTO v_emp_record;

EXIT WHEN c%NOTFOUND;

UPDATE EMP SET sal = p_sal WHERE ROWID = v_emp_record.rd;

v_rows := SQL%ROWCOUNT;

dbms_output.put_line(v_rows);

END LOOP;

COMMIT;

CLOSE c;

END ps_cursor_no_for_update;

此过程游标的查询条件仍未sal=1000,而打开游标的select语句,没有for update子句,游标数据使用rowid作为唯一标识作更新操作

六、测试ps_cursor_no_for_update

先将emp表的sal字段初始化为1000

SQL> update emp t set t.sal=1000;

14 rows updated

SQL> commit;

Commit complete

Emp表的sal字段初始化为1000

查询emp表:

SELECT t.empno, t.ename,t.job, t.sal, ROWID rd from emp t;

结果如下:

图11

Sal字段已经全部更新为1000

编辑存储过程ps_cursor_no_for_update的界面中,设置断点如图12所示:

图12

分别打开2个test窗口,设置输入参数为2000和3000;

窗口1和窗口2分别启动断点调试,并点击run按钮运行,可发现两个窗口都运行到了断点所在位置:

图13

这时,我们在窗口1中单步调试,运行到输出语句一行:

图14

Ok,窗口1停在这里,在窗口2进行相同的动作,发现窗口2的光标仍停在update语句一行,也就是断点所在行;

结论:PL/SQL过程中,打开游标时未使用for update子句时,如果两个进程同时调用该过程,则游标可以同时打开,但在第一个update语句执行后,其它进程则进入等待状态。

好,我们继续将窗口1的过程执行完毕,然后查询emp的数据:

图15

数据已经成功更新为2000;

再看一下窗口2,调试的光标已经移动到了下一行:

图16

说明窗口1的过程执行完毕,被update语句锁住的数据已经解锁,所以窗口的过程可以继续执行了;

将窗口2的过程执行结束,再次查看emp数据:

图17

Sal字段已经更新为3000,说明窗口2的PL/SQL过程更新成功了

七、结论 结论:在PL/SQL过程中打开游标,在未使用for update子句的条件下,多个进程更新相同数据时,可能会出现数据的不一致性,所以在具体实施过程中,要根据具体需求来判断,是否需要使用for update子句。

oracle 10修改游标,Oracle10.2并发条件下更新游标数据的研究相关推荐

  1. List集合多线程并发条件下不安全,如何解决?

    List集合多线程并发 前言 一.List集合使用模拟并发测试 1.1 单线程环境下 1.2 多线程环境下 二.解决方案 2.1 使用Vector类 2.1 使用Collections.synchro ...

  2. 直接修改html文本页面没变化,VUE 直接通过JS 修改html对象的值导致没有更新到数据中解决方法分析...

    本文实例讲述了VUE 直接通过JS 修改html对象的值导致没有更新到数据中解决方法.分享给大家供大家参考,具体如下: 业务场景 我们在使用vue 编写 代码时,我们有一个 多行文本框控件,希望在页面 ...

  3. 《炬丰科技-半导体工艺》硅片清洗条件下薄氧化物特性的研究

    书籍:<炬丰科技-半导体工艺> 文章:硅片清洗条件下薄氧化物特性的研究 编号:JFKJ-21-550 作者:炬丰科技 摘要 栅极氧化物的特性很大程度上取决于清洗过程中使用的最后一种化学溶液 ...

  4. oracle条件批量更新表数据

    更新表数据,当t2.t3的条件符合时更新t1为null update table_name t set t.t1 = null where t.t2 = '是' or t.t3='否' 在plsql工 ...

  5. Mysql更新计数器_MySQL实现计数器如何在高并发场景下更新并保持数据正确性

    一张表 两个字段 一个id 一个useCount 表里存了100个id 每个id对应自己的useCount 业务场景是:当id每使用一次 useCount要加1. 当useCount大于1000时 这 ...

  6. oracle 10修改字符集,Oracle 10g修改数据库字符集

    查看当前字符集 引用 SQL> select * from nls_database_parameters where parameter like '%SET%'; PARAMETER     ...

  7. 高并发场景下更新数据库报错,记录一次 MySQL 死锁问题的解决

    作者 l 会点代码的大叔(CodeDaShu) 今天隔壁项目组的开发小姐姐找到我,说她们项目正在做压力测试,更新 MySQL 数据库的一张表时,总是发生死锁,日志大概是这个样子的: org.sprin ...

  8. php foreach 为什么在if条件下多条数据只取出一条数据_微信大牛教你深入了解数据库索引...

    ​| 作者 刘国斌,腾讯微信事业群研发工程师,目前从事企业微信的后台研发工作,已经参与企业微信消息系统.群聊.客户联系等企业微信多个核心功能的迭代. 数据库查询是数据库的最主要功能之一.我们都希望查询 ...

  9. mysql 并发避免锁表_MYSQL锁表的用法,防止并发情况下的重复数据

    项目中有些使用的redis存储,当对redis进行rehash的时候感觉是比较麻烦的.于是写了个简单的读取redis到数据库的关键方法.仅供参考. package com.redis.web; imp ...

  10. mysql 并发锁表_MySQL锁表的用法,防止并发情况下的重复数据

    早就听说lock tables和unlock tables这两个命令,从字面也大体知道,前者的作用是锁定表,后者的作用是解除锁定.但是具体如何用,怎么用,不太清楚.今天详细研究了下,总算搞明白了2者的 ...

最新文章

  1. python安装进度条不动_python – tkinter中的进度条不起作用
  2. UA MATH564 概率论 样本均值的偏度与峰度
  3. CF-1023F.Mobile Phone Network(并查集缩点)
  4. webService学习7:调用天气接口
  5. Typecho 新浪登陆插件 Sinauth
  6. ASP.NET Core 1.1 简介
  7. linux上git克隆命令,Git clone命令用法
  8. 8月23号刚刚发布的 Flink 1.9 到底优化了哪些功能?
  9. netty : Max frame length of 65536 has been exceeded.
  10. 域用用户怎么允许共享_w7如何共享打印机 w7共享打印机步骤【详细介绍】
  11. Hashtable 和 HashMap 的区别
  12. as5.4安装gcc和g++
  13. 可拖动的进度条_视频号全新升级!进度条可拖动、支持@、支持转发......
  14. 面向对象封装的web服务器
  15. 图灵机器人和ichat
  16. Hadoop学习心得一
  17. EOS官方钱包keosd
  18. 怎么在图片上编辑文字?超简单的两种编辑方法都教给你。
  19. 汇智创科机器人,【汇智创科机器人】这个周六,和孩子一起“动手不动口”,比比看谁最棒!...
  20. iOS 开发常见崩溃分析

热门文章

  1. 使用 C# 开发智能手机软件:推箱子(十)
  2. python跨平台处理绝对路径和相对路径,open,with
  3. 2月25日 局域不变特征的目标跟踪,SURF算子,KLT算子
  4. batch norm参数
  5. springcloud 心得记录
  6. shell介绍,date命令,shell变量
  7. java导出简单写法
  8. 快速实现python c扩展模块
  9. 《Java技术》第四次作业
  10. 一个APP开发有那么难吗?