前一阵子的道拉吉里峰山难,让我这个伪户外爱好者花了不少时间对于登山运动做了一个了解,第一次深刻的感慨于梦想的惊人牵引力,我花了一个周末的时候通读了8264上面的两个帖子,一是马甲KingStone的批判此次道拉吉里峰领队杨春风的帖子,所谓一石激起万层浪,各人对于雪山的热爱,对于征服14座8000米高山的欲望,甚至于在梦想与家庭,与生命的选择上都有着不同的诠释,继而通读了青衣佐刀的《我的09珠峰攀登,活着真好》,虽然有些矫情,但确实让我这个外行人足够震撼。我从来没有想象过,为了一个登顶的梦想,可以花费数年甚至数几十年的准备,可以在上有老下有小,在明知道有生命危险的情况下,依旧砸下几十万甚至上百万的人民币,把生命交托给一个所谓的高山探险公司,所谓的一个领队,所谓的几个夏尔巴人,然后迈向山顶。曾经认为,脑子坏了吧?现在我可以朦胧的感觉,或许这就是梦想,当挣扎在生死边缘想起家人,朋友的时候,当跨上山顶,所谓的空气稀薄地带俯视大地的时候,当看到前辈们的尸体出现在路绳边的时候,当用半辈子时间征服完那14座高山的时候,那是一种什么样的感受?或许是一种灵魂的洗礼,对于人性的全新的认知,我只能够通过看帖子看照片来揣摩,正如山友所述,没有登过山的人永远无法体会面朝大山的感觉。可惜我这辈子都与登山无缘。

感慨颇多,却无以用文字阐述,无论如何,愿此次最终留在大山上没能下来的韩昕、李斌、赵亮能够安息,也希望那些疯狂追逐14座8K梦想的山友们在出发前,能够深深的看看你的父母妻儿的眼神,如果有泪光,那么请扔下行囊,让梦想深埋起来吧!

Oracle数据一致性之锁机制(三)

 技术学习  没有评论 »
262010
 

数据字典锁(data dictionary lock,DDL)的作用是在执行 DDL 操作时对被修改的方案对象或其引用对象的定义进行保护。DDL 锁可以分为三类:排他 DDL 锁(exclusive DDL lock),共享 DDL 锁(share DDL lock),及可解除的解析锁(breakable parse lock)。

当执行以下语句:AUDIT,NOAUDIT,COMMENT,Create [OR REPLACE] VIEW/ PROCEDURE/PACKAGE/PACKAGE BODY/FUNCTION/ TRIGGER,Create SYNONYM,及 Create TABLE(没有使用 CLUSTER 参数时)时,会产生共享 DDL 锁(share DDL lock),而其他的DDL语句产生的都是排他 DDL 锁(exclusive DDL lock),而解析锁是在 SQL 语句执行的解析阶段(parse phase)获得的,当其他DDL操作造成与此锁产生冲突时候,此锁会被解除,所以称之为可解除的解析锁(breakable parse lock)。

对簇(cluster)执行的 DDL 操作需要获取簇及簇内所有表及物化视图上的排他 DDL 锁(exclusive DDL lock)。对簇内表及物化视图的 DDL 操作需要获取簇上的共享 DDL 锁(share DDL lock),以及表或物化视图上的共享 DDL 锁或排他 DDL 锁。簇上的共享 DDL 锁能够防止操作期间其他 DDL 操作将簇移除。

这些比较难以通过实验来查看,所以了解下概念即可。

闩锁(latche)及内部锁(internal lock)的作用是保护数据库及其内存结构。闩锁(latche)是一种简单的底层串行化机制,用于保护 SGA 内的共享数据结构。内部锁(internal lock)更高层且复杂,分为三类,

数据字典缓存锁(dictionary cache lock):当用户更新或使用时数据字典缓存内的条目(entry)时获取,作用是确保正在被解析的语句不会看到不一致的对象定义。语句解析结束时释放。
文件及重做日志管理锁:用于保护各种文件,例如,保护控制文件(control file)的锁,确保同一时间只有一个进程能够对其进行修改。还有协调重做日志文件(redo log file)使用与归档的锁。以及数据文件(datafile)锁,实现多实例在共享模式下挂载数据库,或一个实例在排他模式下挂载数据库。
表空间及回滚段锁:用于保护表空间及回滚段(rollback segment)。例如,一个表空间处于联机(online)还是脱机(offline)状态对访问同一数据库的所有实例应该是一致的。回滚段上的锁保证 同一时间只有一个实例能够对其执行写操作。

在管理锁时,Oracle 提供了一个 DBMS_LOCK 的 Package,详细可参考:http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_lock.htm#CHDICHDC#CHDICHDC

Oracle数据一致性之锁机制(二)

 技术学习  没有评论 »
242010
 

表级锁(TM)具有以下几种模式:行共享(row share,RS),行排他(row exclusive,RX),共享(share,S),共享行排他(share row exclusive,SRX),及排他(exclusive,X)。

表级锁之前的关联可参考下图:

我们可以通过 v$lock, dba_objects 来得知产生锁的 object 是哪个,产生了什么类型的锁,举例如下

SQL> update SONIC_TEST set VALUE=’CCCC’ where ID=1;

1 row updated

SQL> select l.TYPE,
2 decode(l.lmode,
3 0,’None’,
4 1,’Null’,
5 2,’Row-S’,
6 3,’Row-X’,
7 4,’Share’,
8 5,’S/Row-X’,
9 6,’Exclusive’,
10 ‘Unknown’) LockMode,
11 decode(l.request,
12 0,’None’,
13 1,’Null’,
14 2,’Row-S’,
15 3,’Row-X’,
16 4,’Share’,
17 5,’S/Row-X’,
18 6,’Exclusive’,
19 ‘Unknown’) RequestMode,
20 o.OWNER,
21 o.OBJECT_NAME,
22 o.OBJECT_TYPE
23 from v$lock l, dba_objects o
24 where l.ID1 = o.OBJECT_ID
25 and l.SID = 42;

TYPE LOCKMODE REQUESTMODE OWNER OBJECT_NAME OBJECT_TYPE
—- ——— ———- ———- ————— ————
TM Row-X None SYSTEM SONIC_TEST TABLE

Oracle数据一致性之锁机制(一)

 技术学习  没有评论 »
202010
 

先来了解一下锁的概念,锁是保证数据一致性的一种机制,其实现过程由oracle自动完成,多用户模式下,锁有两种模式:

排他锁(exclusive lock)模式:能够阻止共享被加锁的资源。对数据进行修改时必须获得此种模式的锁。第一个排他地对资源加锁的事物是唯一可以对此资源进行修改的事物,直至排他锁被释放。
共享锁(share lock)模式:依据操作类型有条件地允许共享被加锁的资源。对数据进行读取的多个用户可共享此数据,这些用户可以对资源加以共享锁,防止其他用户并发地修改此资源(对数据进行修改的用户需要排他锁)。多个事务可以对相同的资源加共享锁。

锁有三种类型:

DML锁(数据锁):DML锁的作用是保护数据。例如,表级锁(table lock)对整个表加锁,行级锁(row lock)则对选定的数据行加锁。
DDL锁(数据字典锁):DDL锁的作用是保护方案对象的结构。例如,表及视图的定义。
内部锁(internal lock)及闩锁(latch):内部锁及闩锁用于保护数据库的内部结构,例如,数据文件。内部锁及闩锁的管理完全由 oracle 自动完成。

继续细化,DML锁分为:

行级锁(TX):作用是防止两个事务同时修改相同的数据行。当一个事务需要修改一行数据时,就需对此行数据加锁。此为粒度最精细的锁。
表级锁(TM):作用是对并发的 DDL 操作进行访问控制,例如防止在 DML 语句执行期间相关的表被变更或移除。表级锁(TM)具备一下几种模式:行共享(row share,RS),行排他(row exclusive,RX),共享(share,S),共享行排他(share row exclusive,SRX),及排他(exclusive,X)

我们来做个测试,打开一个Session并且获得此Session ID为38,先执行查询

SQL> select * from SONIC_TEST;

ID VALUE
——- —-
1 AAAA
2 BBBB

事务A开始对第一行update,但是暂不提交

SQL> update SONIC_TEST set VALUE='CCCC' where ID=1;

1 row updated

查看此时生成的锁的情况

SQL> select TYPE,LMODE,REQUEST from v$lock where SID=38;

TYPE LMODE REQUEST
—- ———- ———-
TM 3 0
TX 6 0

发现事务A(Session ID=42)产生了两个锁,类型为 TM 与 TX,然后打开事务B,针对ID=1的行进行操作

SQL> update SONIC_TEST set VALUE='DDDD' where ID=1;

发现此条语句并不执行,查看此Session的状态

SQL> select sid,status,event,state from v$session where SID=42;

SID STATUS EVENT STATE
———- ——- ——————————— ——————-
42 ACTIVE enq: TX - row lock contention WAITING

看到此事务在等待TX锁,这就是行级锁(TX)的作用,若此时事务B针对ID=2的行进行操作

SQL> update SONIC_TEST set VALUE='CCCC' where ID=2;

1 row updated

可以看到可以成功 update,由此可见,行级锁(TX)只对数据所在行做锁定

再来看一下另外一个表级锁(TM)的作用,同样如果在事务A还没有提交的时候,如果事务B对该表进行DDL操作,比如说drop该表

SQL> drop table SONIC_TEST purge;

drop table SONIC_TEST purge

orA-00054: resource busy and acquire with NOWAIT specified

会报错,提示资源繁忙,这就是表级锁(TM)的作用。

Oracle数据一致性之事务隔离级别

 技术学习  没有评论 »
192010
 

自认为对 oracle Concept 已经有了比较不错的了解,陆续跟一些资深的 DBA 谈到底层的运作机制跟实现原理的时候,才发现基础依旧不够扎实,故准备花点时间从头过一遍 Concept,并且将理论通过实验来逐一验证,先从数据的一致性开始。

ANSI/ISO SQL 标准(SQL92)定义了四种事务隔离级别,分别为 Read uncommitted, Read committed, Repeatable read, Serializable,此四种隔离级别是针对多用户模式下出现的三种现象所定义,此三种现象分别为 dirty read, nonrepeatable read, phantom read

dirty read(脏读)是指一个事务读取了被其他事务写入但还未提交的数据。
nonrepeatable read(不可重复读)是指一个事务再次读取其之前曾经读取过的数据时,发现数据已被其他已提交的事务修改或删除。
phantom read(幻想读)是指事务按照之前的条件重新查询时,返回的结果集中包含其他已提交事务插入的满足条件的新数据。

oracle 支持其中两种 Read committed 和 Serializable,并且额外添加一种为 Read only。

Read committed 是 oracle 默认的事务隔离级别,做个测试来看下针对三种现象的处理方式

SQL> create table SONIC_TEST (C1 varchar(5));

Table created

SQL> insert into SONIC_TEST values (‘AAAA’);

1 row inserted

SQL> commit;

Commit complete

事务A执行查询

SQL> select * from SONIC_TEST;

C1
—-
AAAA

切换事务B执行update但是没有commit

SQL> update SONIC_TEST set C1=’BBBB’;

1 row updated

回到事务A再次执行查询

SQL> select * from SONIC_TEST;

C1
—-
AAAA

显然事务隔离级别 Read committed 阻止了 dirty read,继续

此时事务B执行commit,然后再回到事务A,进行同样的查询

SQL> select * from SONIC_TEST;

C1
—-
BBBB

这时候数据产生了变化,也就是说 Read committed 没有阻止 nonrepeatable read,继续

事务B中进行一个insert语句

SQL> insert into SONIC_TEST values (‘CCCC’);

1 row inserted

SQL> commit;

Commit complete

回到事务A再次用同样语句查询

SQL> select * from SONIC_TEST;

C1
—-
BBBB
CCCC

显然 Read committed 也没有阻止 phantom read

—————————————————-我是分割线———————————-

我们继续对事务隔离级别 Serializable 做同样的测试:

将数据恢复到原始状态,并且事务A的隔离级别调整为 Serializable

SQL> truncate table SONIC_TEST;

Table truncated

SQL> insert into SONIC_TEST values (‘AAAA’);

1 row inserted

SQL> commit;

Commit complete

SQL> alter session set isolation_level=serializable;

Session altered

SQL> select * from SONIC_TEST;

C1
—-
AAAA

切换到事务B,执行update操作但是不执行commit

SQL> update SONIC_TEST set C1=’BBBB’;

1 row updated

回到事务A,重新查询

SQL> select * from SONIC_TEST;

C1
—-
AAAA

显然事务隔离级别 Serializable 也阻止了 dirty read,继续

此时事务B执行commit,然后再回到事务A,进行同样的查询

SQL> select * from SONIC_TEST;

C1
—-
AAAA

这时候发现虽然事务B中对数据进行了更改,并且commit,但是事务A中读取到的依旧是做修改前的数据,这个表明事务隔离级别 Read committed 阻止了 nonrepeatable read,继续

事务B中进行insert

SQL> insert into SONIC_TEST values (‘CCCC’);

1 row inserted

SQL> commit;

Commit complete

返回事务A再次查询

SQL> select * from SONIC_TEST;

C1
—-
AAAA

数据依旧没有变化,表明事务隔离级别 Read committed 同样阻止了 phantom read。

结合测试,我们很容易得出结论
已提交读取(read committed)允许 dirty read,不允许 read uncommitted,不允许 phantom read
串行化(rerializable)不允许 dirty read,不允许 read uncommitted,不允许 phantom read

而如果在同时支持此四种事务隔离级别的 SQL Server 中对另外两种隔离级别也做测试,会得出最后的结论如下

这个时候表 SONIC_TEST 中的数据实际上已经被变更了,但是事务A因为运行在 rerializable 隔离级别下,所以查询出来的结果依旧是修改前的,那么如果这个时候事务A如果也对该表做 update 操作会发生什么情况呢?继续测试

事务A中对表进行update操作

SQL> update SONIC_TEST set C1=’DDDD’;

update SONIC_TEST set C1=’DDDD’

ora-08177: can’t serialize access for this transaction

出现 ora-08177 错误,更新失败,那么 oracle 具体是如何来控制这样的机制的呢?且听下回分解:)

关于脏读

 技术学习  2 条评论 »
072010
 

昨天跟微软的 SQL Server 工程师聊到“脏读(Dirty Read)”,一时居然无法准确明了的做出回应,后来查了些相关资料,做了下简单了解。

所谓脏读,就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。而这个数据在 SQL Server 中就定义脏数据(Dirty Data)

而作为 DBA,我平时所接触到的 oracle 中所谓的脏数据是指依旧某些尚存在内存中,还没被 DBWR 进程写到数据文件中的数据,如此看来两者对于脏数据的定于还是存在偏差。

事实上,从目前的 oracle 的机制来看,Oracle 是不支持脏读的,当事务A对某张表中的数据进行修改,并且尚没有 Commit 之前,若事务B去查询这张表的信息,看到的将是旧的数据,若此时事务B区对这张表的数据进行更新,会发现命令停在那里不执行下去了,产生了一个等待事件,直到事务A进行 Commit 或者 Rollback 之后,事务B才会执行,这样做的目的就是为了保证数据的一致性。做个简单的测试如下,环境为 oracle 10g

SQL> create table sonic_dirty_oracle (C1 varchar2(10));

Table created

SQL> insert into sonic_dirty_oracle values ('AAA');

1 row inserted

SQL> commit;

Commit complete

事务A(SID=38)

SQL> select C1 from sonic_dirty_oracle;

C1
———-
AAA

SQL> update sonic_dirty_oracle set C1='BBB' where C1='AAA';

1 row updated

- 这个时候没有 Commit

SQL> select C1 from sonic_dirty_oracle;

C1
———-
BBB

事务B(SID=39)

SQL> select C1 from sonic_dirty_oracle;

C1
———-
AAA

SQL> update sonic_dirty_oracle set C1='CCC' where C1='AAA';

此时事务B没能执行完成,停在那里不动

现在来看事务B的状态:

SQL> select event,state from v$session where sid='38';

EVENT STATE
————————————- ——-
enq: TX - row lock contention WAITING

可见,事务A产生了一个TX Row Lock,只有等事务A做了 Commit 之后,事务B才会执行完这条命令

同样来看 SQL Server ,环境为 SQL Server 2008

SQL> create table sonic_dirty_sqlserver (C1 varchar(10));

Command(s) completed successfully.

SQL> insert into sonic_dirty_sqlserver values ('AAA');

(1 row(s) affected)

事务A

SQL> begin tran
SQL> update sonic_dirty_sqlserver set C1='BBB' where C1='AAA';

(1 row(s) affected)

- 这个时候没有 Commit

事务B

SQL> select * from sonic_dirty_sqlserver;

- 发现居然无法执行,一条未 Commit 的 update 语句,将整个表锁起来,甚至无法做查询

SQL> select * from sonic_dirty_sqlserver with (nolock);

C1
———-
BBB

- 当加了 with (nolock) 之后出来的结果就是脏读,读到的是这条尚未被提交的脏数据

存在便是合理,既然 SQL Server 有脏读的概念,一定有其用武之地,比如针对金融行业的复杂的业务逻辑当中,只是我目前还无法举出很好的例子来,学海无涯,继续坐舟

Powered by WordPress 3.3.1 CopyRight 2004~2012, Sonic Tang

虚拟主机赞助商:海波,苏ICP备11082989号

Suffusion theme by Sayontan Sinha