暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

GBase8sV8.8锁与隔离级别的详细介绍

原创 努力努力再努力 2024-10-19
245

一、锁及锁的类型

1.锁机制

  • 在多用户数据库系统中,用户可以锁定一个对象,可以防止其他用户修改锁定的对象
  • 多个并发用户访问数据库数据的情况下,为了保证数据的完整性,锁是必需的
  • 锁作为关联到数据项的对象,程序可以显示对数据加锁,数据库系统也可以隐式的对对象进行加锁

2.锁的分类

  • Shared locks: 共享锁,多个用户可以同时读取相同的记录
  • Exclusive locks: 排他锁,同一时间仅仅有一个用户可以读取相同的记录
  • Promotable (Update) lock: 提升锁,可以升级 (从共享锁提升为排他锁) 或者降级
  • Intent lock: 专一锁,是一种表级锁,标识在该表上有一个游标在读取数据

3.锁的类型介绍

(1)共享锁(lock-S)

  • 如果一个对象上没有排他锁,则共享锁可以加在该对象上
  • 防止其他事务更新数据
  • 但同时,其他事务可以读取该数据 (其他事务可以加共享锁)
  • 多个事务可以在同一个对象上加多个共享锁

(2)排他锁 (lock-X)

  • 如果记录上没有任何锁,排他锁才可以加在该对象上
  • 一旦在记录上加了排他锁,则不能在该记录上增加任何锁了,直至锁释放
  • 防止其他事务读取和更修数据

(3)更新锁 (lock-U)

  • 在更新Cursor中使用
  • 更新锁由cursors 含有 ‘for update’ 选项执行时产生的 ,只能在没有排他锁或者更新锁的记录上加更新锁
  • 当锁定的记录真正执行的时候,更新锁将提升为排他锁

(4)专一锁 (lock-IX or IS)

  • 由IDS自动分配
  • 如果一条记录上的记录被更新,一个排他锁将分配在该记录上,同时将该记录的表上自动加上专一锁
  • 这能保证没有session可以在该表上增加排他锁,只要该表中有记录被增加了排他锁

4.锁的兼容矩阵

S

X

S

TRUE

FALSE

X

FALSE

FALSE

5.锁的有效期

  • 程序控制数据库锁的有效期,当数据库关闭后,数据库锁将被释放
  • 根据数据库是否使用了事务的情况,表锁的有效期不同【如果数据没有使用事务(没有事务日志,也不使用commit work语句),显示对一个表lock,当执行unload table时,锁将被释放;】
  • 当数据库使用了事务,事务结束时,将释放事务所有的锁 table, row, page, and index locks

6.锁的粒度及应用

(1)锁的粒度介绍

锁粒度

说明

数据库锁

针对整个数据库的锁

表锁

针对整个表的锁

页锁

针对整页数据的锁

行锁

针对一个数据行的锁

字节锁

在包含varchar的行上的锁

键锁

在索引中的一个键值上的锁

 

(2)不同锁粒度的应用

一般来讲,锁的粒度越大,并发性就越低,程序控制将越简单。

数据库锁应用

数据库管理活动,比如: imports 和 exports

  • 表锁应用

当整个表或者表的大部分数据需要更新,加表级锁效率高

  • 页级锁应用

当按数据物理顺序进行访问和更新时,页级锁效率高

  • 行级锁应用

OLTP 事务采用行级锁,效率高

以下语句将隐式的对表加锁,直到事务结束后释放:

ALTER FRAGMENT

ALTER INDEX

ALTER TABLE

CREATE INDEX (if not using ONLINE keyword)

DROP INDEX (if not using ONLINE keyword)

RENAME COLUMN

RENAME TABLE

(3)哪种锁粒度是最优的?取决于事务本身的特点

  • 当更新表中相对较小一部分数据的时候,采用行级锁将获取最好的性能
  • 如果一个事务只访问表中一小部分数据,那就采用行级锁
  • 如果一个事务频繁的访问整个表的数据,设置更粗的粒度,比如表级锁
  • 如果更新数据库中大部分表的大部分数据的情况下, 采用数据库级别的锁

(4)关于查看锁及事务情况的指令

  • 查看表锁模式:

oncheck –pt dbname:tablename

dbschema –d dbname –t tablename -ss

  • 查看用户进程锁等待情况使用: onstat –u
  • 查看锁使用和等待情况使用: onstat -k
  • 监控数据库事务及其状态使用: onstat -x

二、隔离级别的介绍

  • 多个同时运行的事物之间不会互相影响彼此的执行
  • 每个用户感觉自己的事务都是排他的执行
  • 同时发生的其他事务应该出现在当前事务的前或者后
  • 类似一个事务中的“序列”

1.脏读

设置方式:SET ISOLATION TO DIRTY READ;

  • 采用这种隔离级别,数据库服务器不会分配任何锁
  • 查询过程中,可以查询到任何数据row, 甚至那些被修改但尚未提交的记录
  • Dirty-read隔离级别将产生幻影读,不可重复读的问题
  • 非日志数据库中只有Dirty-read一种隔离级别
  • Dirty-read 隔离级别应用场景

静态表 (no updates, read-only tables)

速度比100% 准确更重要的情况

不能等待锁的释放

2.可提交读

设置方式:SET ISOLATION TO COMMITTED READ;

  • 确保读取的所有记录都是提交到数据库
  • 能避免读到脏数据
  • 读到的所有的记录都是已提交的
  • 当一个进程读完记录后,其他进程就可以修改
  • 在读取数据前,数据库server尝试在记录上加共享锁

加锁前,需要先检查是否可以对对象加共享锁,但是不加

如果可以加锁,则要保证要加锁的记录没有其他进程正在更新

  • 当记录正在更新时,记录上有排他锁,此时我们不能对这些记录加共享锁

3.游标读

设置方式:SET ISOLATION TO CURSOR STABILITY;

  • 非更新CURSOR, 游标读的所有记录加上共享锁
  • 共享锁一致将保持,直到下一行记录被读取
  • 通过游标检索数据, 共享锁将一直保持到执行下一个 FETCH语句
  • 不仅可以看到提交的记录,也可以保证看到的记录不会被更新
  • 其他进程不能更新 (UPDATE or DELETE) 你所看到的记录
  • 当移动到下一行时,锁才会释放,记录就可以进行修改

4.可重复读

设置方式:SET ISOLATION TO REPEATABLE READ;

  • 数据库在读取的记录上加共享锁,验证是否可以读取数据
  • 直到事务提交,锁才能释放
  • 其他用户可以读取数据,但是不能修改
  • 可以保证在同一事务中前后两次读取记录是一致的
  • 当你必须要信任所有读取的记录,保证记录不被修改。我们可以采用repeatable read. 举例:

关键的, 统计数据 (如:银行账号的余额情况)

关联查询多个表

5.最后可提交读

设置方式:SET ISOLATION TO COMMITTED READ LAST COMMITTED

  • 解决Committed Read的不足: 记录被锁,其他进程需要等待;更新的记录不能访问,直到提交,除非采用脏读;由于需要等待更新记录的提交,应用程序性能较低;如果采用脏读则会得到非预期的结果;死锁的发生,也会消耗很多时间

解决办法: Last Committed Read

  • Committed Read 隔离级别, 由于其他session在记录上加了排他锁(行级锁),将导致读取数据失败SET ISOLATION COMMITTED READ 的LAST COMMITTED 可以降低读取数据的锁冲突

6.监控session的隔离级别指令

使用: onstat –g sql 或者 onstat –g ses

查看sid的详细信息: onstat –g sql sid

7.关于隔离级别的示例

(1)脏读

优点:并发性高,不需要锁资源 缺点:脏读、幻影读、不可重复读

Session1

Session2

Session2 output

Begin work;

--With committed read default

Begin work;

Set isolation dirty read;

Select * from lock_tb where c1<=3;

1 abc

2 abc

Update lock_tb set c2='new' where c1=1;

Select * from lock_tb where c1<=3;

1 new

2 abc

Insert into lock_tb values(3, 'new');

Select * from lock_tb where c1<=3;

1 new

2 abc

3 new

Rollback;

Select * from lock_tb where c1<=3;

1 abc

2 abc

--或者

Commit work;

Select * from lock_tb where c1<=3;

1 new

2 abc

3 new

(2)可提交读

优点:相对dirty read能避免脏读的问题

缺点:并发性较dirty read有所降低,容易出现锁等待引起的问题。不能解决幻影读、不可重复读

Session1

Session2

Session2output

Begin work;

--With committed read default

set lock mode to wait 5;

Begin work;

set isolation committed read;

set lock mode to wait 5;

Select * from lock_tb where c1<=3;

1 abc

2 abc

Update lock_tb set c2='new' where c1=1;

Select * from lock_tb where c1<=3;

SQL Error -244 锁错误

以上现象解释如下:

  • 因为 session2采用committed read对读取的记录不加S-LOCK,所以session1可以对该记录进行更新,并在该记录上加X-LOCK
  • session2采用committed read对读取的记录试图加S-LOCK,但检测到c1=1的记录上有X-LOCK,出现锁等待事件,超过锁等待时长5秒后报告锁等待超时错误:Error -244

Session1

Session2

Session2output

Begin work;

--With committed read default

Set lock mode to wait 5;

Begin work;

Set isolation committed read;

Set lock mode to wait 5;

Select * from lock_tb;

1 abc

2 abc

update lock_tb set c2='new' where c1=1;

insert into lock_tb values(3, 'new');

Commit work;

Select * from lock_tb;

当session 1结束后执行

1 new

2 abc

3 new

--或者

Roll back;

Select * from lock_tb;

当session 1结束后执行

1 abc

2 abc

(3)可重复读

优点:能够解决脏读、幻影读和不可重复读的问题

缺点:只能串行执行,并发性低,需要对读取的记录加s-lock,容易引起锁相关的问题

Session1

Session2

Session2output

Begin work;

--With committed read default

set lock mode to wait 5;

Begin work;

set isolation repeatable read;

Set lock mode to wait 5;

Update lock_tb set c2='new' where c1=1;

Select * from lock_tb where c1<=3;

SQL Error -244 锁错误

Insert into lock_tb values(3, 'new');

Commit work; 

以上原因如下:

  • Session1对修改的的记录(c1=1)加X-LOCK
  • session2采用repeatable read需要对读取的记录(c1<=3)加S-LOCK,但是记录c1=1已经被加上了x-lock,故出现锁等待事件,当锁等待超时,则报告锁错误:Error -244

Session1

Session2

Session2output

Begin work;

--With committed read default

Set lock mode to wait 5;

Begin work;

Set isolation repeatable read;

Set lock mode to wait 5;

Update lock_tb set c2='new‘ where c1=1;

Insert into lock_tb values(3, 'new');

Commit work; 

Select * from lock_tb ;

1 new

2 abc

3 new

--或者:

Rollback;

Select * from lock_tb ;

1 abc

2 abc

(4)最后可提交读

优点:能解决脏读问题,并发性高;不需要锁资源,能避免committed read带来的锁问题,

缺点:幻影读、不可重复读

Session1

Session2

Session3    

Begin work;

--With committed read default

set lock mode to wait 5;

Begin work;

set isolation to committed read last committed;

Set lock mode to wait 5;

Select * from lock_tb where c1>=3;

1 abc

2 abc

update lock_tb set c2='new' where c1=1;

select * from lock_tb where c1>=3;

1 abc

2 abc

Update lock_tb set c2='new' where c1=1;

Select * from lock_tb where c1>=3;

1 abc

2 abc

rollback; 

Select * from lock_tb where c1>=3;

1 abc

2 abc

--或者

Commit work;

Select * from lock_tb where c1>=3;

1 new

2 abc

3 new

最后修改时间:2024-10-19 10:37:37
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论