从事数据库工作多年,目前看好分布式NeSQL/HTAP数据库在企业客户市场的发展。未来的主要方向是——致力于 NewSQL/HTAP 数据库的推广普及。
分类: Sybase
2013-09-24 14:21:49
运行在隔离级别2(Repeatable Read))下的事务不会发生"脏读"和"不可重复读"问题。下面将结合一些例子讲述ASE实现该隔离级别的基本原理。让我们看一个例子,假设事务TA执行如下操作:
begin transaction
.....
select balance from accounts where actno='1234567' --第一次读取
.....
select balance from accounts where actno='1234567' --第二次读取
commit
事务TA在第1次执行查询时得到账号'1234567'的余额假设是1000;在其第2次执行相同查询语句之前,事务TB执行如下语句:
begin transaction
......
update accounts set balance=balance+100 where actno='1234567'
commit
假设TA中的第一次读取先执行,在它执行完后、第二次读取执行之前,TB中的update语句执行。TA和TB都是非链式模式,TA运行在隔离级别2下,TB运行在隔离级别1下,表accounts采用"datarows"锁定机制。
由于事务TA运行在隔离级别2下,当执行头一个select语句时,ASE会对actno='1234567' 对应的记录行加"共享行锁(Sh_row)",此外还会加"共享意向锁",因为account表加了"共享行锁"(注意:在隔离级别1下,对于这个select语句是不会加共享行锁的,因此也就不会加共享意向锁)。当事务TB执行update语句更新actno='1234567'对应的数据行时需要加"排它行锁(Ex_row)",但TA已经在这条记录上持有"共享行锁",因此TB发出的"排它行锁"请求不能成功,被"阻塞"。TB中的update语句由于"阻塞"而不能执行,直到事务TA释放了所持有的"共享行锁"。因此,事务TA读取的数据就不会被TB修改。当TA事务第二次执行select查询时读到的数据也就与第一次读取到的数据保持一致,从而实现了隔离级别2所要求的可重复读。此外,如果TB事务中执行的update语句替换为delete accounts where actno='1234567'语句,delete语句同样也需要请求"排他行锁",因此道理是一样的。
需要注意的是:ASE隔离级别2只支持"数据行锁定(datarows locking)"或"数据页(datapages locking)"表。
概念解释:意向锁 (Intent lock) 。意向锁指示某个表上当前持有行级锁(或页级锁)。ASE会对每个有共享行(或页)锁或排它行(或页)锁的表应用一个意向锁。一个连接上运行的事务,不管表上有多少个行锁或页锁,该表上只有一个意向锁。意向锁可以是"排它意向锁",也可以是"共享意向锁"。
设置"意向锁"可阻止其它事务在包含有"行级锁"或"页级锁"的表上获取有冲突的"表级锁"。只要行锁或页锁对事务有效,就会持有意向锁。
此外,在隔离级别2(或3)下,如果select查询使用noholdlock选项的话,那么在事务中这个语句执行完后不会加共享锁,但是带有noholdlock的select查询在执行期间,如果命中的记录上有"排它行锁",那么一样会阻塞。我们看一个例子,假如accounts表采用Datarows锁定,事务运行在非链式模式、隔离级别1下:
begin tran
...
select * from accounts noholdlock where balance < 4000
...
commit
select语句执行完后,通过sp_lock查看,这个语句没有保持共享行锁。