[20170530]写一致问题.txt

简介: [20170530]写一致问题.txt --//oracle 通过undo等保持读一致性. --//假如一个回话修改1条记录 y字段+1,另外的回话也修改相同记录,y字段+1.
[20170530]写一致问题.txt

--//oracle 通过undo等保持读一致性.
--//假如一个回话修改1条记录 y字段+1,另外的回话也修改相同记录,y字段+1.
--//这样第2个回话会出现阻塞,等待第1个回话提交或者回滚,当第1个回话提交后,第2个回话会重读y的值,
--//然后再增加1.如果最开始y=0.这样第2个回话显示y=2.上午看了一个系列测试:
raajeshwaran.blogspot.com/2016/06/write-inconsistency-part-i.html
raajeshwaran.blogspot.com/2016/06/write-inconsitency-part-ii.html
raajeshwaran.blogspot.com/2016/06/write-inconsitency-part-iii.html

--//我重复测试.通过一些例子说明问题.

0.环境:
SCOTT@test01p> @ ver1
PORT_STRING          VERSION        BANNER                                                                               CON_ID
-------------------- -------------- -------------------------------------------------------------------------------- ----------
IBMPC/WIN_NT64-9.1.0 12.1.0.1.0     Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production              0

1.测试1:
--//session 1:
--//drop table t purge;
SCOTT@test01p(369,151)> create table t as select 1 x,0 y from dual;
Table created.

SCOTT@test01p(369,151)> insert into t(x,y) values(2,0);
1 row created.

SCOTT@test01p(369,151)> select * from t;
   X          Y
---- ----------
   1          0
   2          0

SCOTT@test01p(369,151)> update t set y = y+1;
2 rows updated.

SCOTT@test01p(369,151)> select * from t;
   X          Y
---- ----------
   1          1
   2          1

--//注意:事务没有提交!!

--//session 2:
SCOTT@test01p> @s
SCOTT@test01p(130,325)> select * from t;
   X          Y
---- ----------
   1          0

--//仅仅看到一条,这是第2个插入还没有提交.
SCOTT@test01p(130,325)> update t set y = y+1;

--//session 2阻塞.回到session 1:
SCOTT@test01p(369,151)> commit;
Commit complete.

SCOTT@test01p(369,151)> select * from t;
   X          Y
---- ----------
   1          1
   2          1
--//回到session 2,修改完成.
SCOTT@test01p(130,325)> update t set y = y+1;
1 row updated.

SCOTT@test01p(130,325)> select * from t;
   X          Y
---- ----------
   1          2
   2          1

--//你可以发现x=2的记录y=1并没有修改,这是因为当时session 2看到1条.

2.测试2:
--//重复前面的测试,但是这次引入触发器:
--//drop table t purge;

create table t as select 1 x,0 y from dual;
create or replace trigger t_trig
before update on t
for each row
begin
   dbms_output.put_line('updating '|| :old.x ||','|| :old.y
            ||' to '|| :new.x || ',' || :new.y );
end;
/

--//session 1:
SCOTT@test01p(369,151)> set serveroutput on
SCOTT@test01p(369,151)> insert into t(x,y) values(2,0);
1 row created.

SCOTT@test01p(369,151)> select * from t;
   X          Y
---- ----------
   1          0
   2          0

SCOTT@test01p(369,151)> update t set y = y+1;
updating 1,0 to 1,1
updating 2,0 to 2,1
2 rows updated.

SCOTT@test01p(369,151)> select * from t;
   X          Y
---- ----------
   1          1
   2          1

--//注意:事务没有提交!!
--//session 2:
SCOTT@test01p(130,325)> set serveroutput on
SCOTT@test01p(130,325)> select * from t;
   X          Y
---- ----------
   1          0

SCOTT@test01p(130,325)> update t set y = y+1;

--//出现阻塞.回到session 1:
--//session 1:
SCOTT@test01p(369,151)> commit ;
Commit complete.

SCOTT@test01p(369,151)> select * from t;
   X          Y
---- ----------
   1          1
   2          1

--//回到session 2:
--//session 2:
SCOTT@test01p(130,325)> update t set y = y+1;
updating 1,0 to 1,1
updating 1,1 to 1,2
updating 2,1 to 2,2
2 rows updated.

SCOTT@test01p(130,325)> select * from t;
   X          Y
---- ----------
   1          2
   2          2

--//你可以发现x=2,y=2,从某种程度认为trigger is evil.从dba角度认为触发器是应用的大忌,从某种角度要尽量避免.
--//lz的解析:
http://raajeshwaran.blogspot.co.id/2016/06/write-inconsitency-part-ii.html

The output from the trigger confirms, the update statement from session#2

a) Did a consistent read on Table 'T'
b) Got the first row for update with x=0 and y=1 and changed y=2 and invoked the trigger before executing the update
   statement (since it is a before update trigger).
c) Trigger put this message "updating 1,0 to 1,1" in buffer
d) Upon trying to make changes to that block, it realizes that row is locked by session#1 and hence this update got
   blocked.
e) When session#1 got committed – this update from session#2 resumes – in-turn got restarted with SCN later than
   commit SCN generated by the first transaction.
· So do again a consistent read, go two rows, modify them, have those before and after values recorded by trigger in
   buffer.

f) Session#2 get current read on block to make changes for new values of Y. (since session#1 got committed, block is
   available for current read to Session#2)
g) For each row updated trigger tries to put message "updating x1, y1 to x2, y2" in buffer
h) Once the update statement completes, message from buffer got printed on screen.

The presence of three message confirms that update got restarted and produced correct results at the end of this
transaction.

The set of columns that "trigger" the restart are the ones used to locate rows (of which there are none, the where
clause doesn't exist) plus any columns referenced in a trigger. Since the trigger refers to X and Y - they become part
of the set of columns responsible for triggering the restart of this update.

--//自己认为不好理解^_^.

3.测试3:
--//重复前面的测试.
--//drop table t purge;

--//session 1:
create table t as select 1 x, 0 y from dual;

SCOTT@test01p(369,151)> insert into t(x,y) values(2,0);

1 row created.

SCOTT@test01p(369,151)> select * from t;
   X          Y
---- ----------
   1          0
   2          0

SCOTT@test01p(369,151)> update t set y = y+1;
2 rows updated.

SCOTT@test01p(369,151)> select * from t;
   X          Y
---- ----------
   1          1
   2          1

--//注意:事务没有提交!!
--//session 2:
SCOTT@test01p(130,325)> select * from t;
   X          Y
---- ----------
   1          0
update t set y = y+1 where x >0 and y is not null;

--//出现阻塞.回到session 1:
--//session 1:
SCOTT@test01p(369,151)> commit ;

Commit complete.

SCOTT@test01p(369,151)> select * from t;
   X          Y
---- ----------
   1          1
   2          1
--//回到session 2:
--//session 2:
SCOTT@test01p(130,325)> update t set y = y+1 where x >0 and y is not null;
2 rows updated.

SCOTT@test01p(130,325)> select * from t;
   X          Y
---- ----------
   1          2
   2          2
--//奇怪吧!这次修改2条记录.lz的解析是oracle的bug

--//lz的解析:
http://raajeshwaran.blogspot.co.id/2016/06/write-inconsitency-part-iii.html

So having the set of columns in where clause "triggers" the transaction restart, which in-turn advances SCN later than
the commit SCN generated by the first transaction.

That is the whole story of getting consistent result after the update from Session#2.

So why this statement "update T set y = y+1"   behaves different from this statement "update T set y = y+1 where x >0
and y is not null"?  (Since both the statement is supposed to update all the rows from the Table T) – This is
identified as an Internal Bug and not yet fixed still in Oracle 12c (12.1.0.2)

So please aware of these and have your DML's to be tested properly in applications, to avoid these kind of
inconsistency, till they get fixed.

4.补充测试:
--//自己做了补充测试只要条件是如下,就修改2条.
SCOTT@test01p(130,325)> update t set y = y+1 where y is not null;
2 rows updated.

--//如下也会
SCOTT@test01p(130,325)> update t set y = y+1 where y>=0;
2 rows updated.

目录
相关文章
通过 ansible 创建 openstack 虚拟机并部署应用(实战篇)
前文 通过 ansible 创建 openstack 虚拟机并部署应用(配置篇) 接下来我们实战一下。 目录结构 ── ansible.cfg├── group_vars│ ├── all.yml├── openstack.
5805 0
|
9月前
|
人工智能 运维 监控
阿里云ACK容器服务生产级可观测体系建设实践
本文整理自2024云栖大会冯诗淳(花名:行疾)的演讲,介绍了阿里云容器服务团队在生产级可观测体系建设方面的实践。冯诗淳详细阐述了容器化架构带来的挑战及解决方案,强调了可观测性对于构建稳健运维体系的重要性。文中提到,阿里云作为亚洲唯一蝉联全球领导者的容器管理平台,其可观测能力在多项关键评测中表现优异,支持AI、容器网络、存储等多个场景的高级容器可观测能力。此外,还介绍了阿里云容器服务在多云管理、成本优化等方面的最新进展,以及即将推出的ACK AI助手2.0,旨在通过智能引擎和专家诊断经验,简化异常数据查找,缩短故障响应时间。
阿里云ACK容器服务生产级可观测体系建设实践
|
Linux 数据处理 Perl
在Linux中,awk命令的如何使用?
在Linux中,awk命令的如何使用?
|
11月前
|
测试技术 API 开发者
精通.NET单元测试:MSTest、xUnit、NUnit全面解析
【10月更文挑战第15天】本文介绍了.NET生态系统中最流行的三种单元测试框架:MSTest、xUnit和NUnit。通过示例代码展示了每种框架的基本用法和特点,帮助开发者根据项目需求和个人偏好选择合适的测试工具。
404 3
|
11月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
155 2
|
SQL 算法 数据库
sql数据库表内容误删怎么恢复
当SQL数据库表的内容误删时,可以尝试以下方法来恢复数据: 首先,最佳的解决方案是使用数据库备份来恢复数据。这是一种重要的防备措施,可在数据意外删除时快速恢复。 1. **使用备份恢复**
|
关系型数据库 MySQL Serverless
MYSQL数字函数:不可不知的数据处理利器
MYSQL数字函数是数据处理的得力助手,高效、准确且灵活。从基础数学运算到复杂数据转换,如ROUND、CEILING、FLOOR等,它们都能轻松胜任。ROUND函数实现数据四舍五入,而CEILING和FLOOR则分别进行向上和向下取整。这些函数不仅提升数据处理效率,还保障数据精确性和一致性。在数据分析、报表生成及业务逻辑处理中,MYSQL数字函数均扮演关键角色。对于数据处理开发者而言,熟练掌握这些函数是不可或缺的技能,它们将极大助力工作并提升职业竞争力。
314 6
|
SQL 消息中间件 JSON
flink kafka connector源码解读(超详细)
为了掌握Flink自定义Connector,本文直接从源码出发,研究Flink的kafka connector是如何实现的?
1439 0
flink kafka connector源码解读(超详细)
|
运维 Cloud Native Java
SLS支持高精度时间戳和全局排序
日志内容本身是一种重要信息,日志之间的相对顺序也是因果关系的一种反映,某些场景下如果日志内容完全相同,但是日志间的顺序错乱了反映出来的结果可能和真实世界里面的事件完全相反。
62625 12
SLS支持高精度时间戳和全局排序
|
机器学习/深度学习
【DR_CAN-MPC学习笔记】2.最优化数学建模推导
【DR_CAN-MPC学习笔记】2.最优化数学建模推导