首页 > 数据库 > 国内数据库 > 南大通用GBase 8s数据库的封锁与并发事务调度
原文链接:
https://www.gbase.cn/community/post/4582
更多精彩内容尽在南大通用
GBase技术社区,南大通用致力于成为用户最信赖的
数据库产品供应商。
本文探讨GBase 8s的事务处理特性,揭示它是如何确保ACID特性,并有效管理并发事务的。
举例说明
两个售票点同时售出同一天同一车次的车票,第一个售票点执行的数据库事务 T1 为:
(1)读出当前车票的剩余数量 A,假设 A=50;
(2)售出一张票,剩余数量变为 A=A-1,即 A=49。
第二个售票点执行的数据库事务 T2 为:
(1)读出当前车票的剩余数量 A,假设 A=50;
(2)售出一张票,剩余数量变为 A=A-1,即 A=49。
事务 T1 和 T2 按照如下顺序并发执行:
(1)读出当前车票的剩余数量 A,假设 A=50;
(2)读出当前车票的剩余数量 A,假设 A=50;
(3)售出一张票,剩余数量变为 A=A-1,即 A=49;
(4)售出一张票,剩余数量变为 A=A-1,即 A=49。
事务执行的结果是只卖了一张车票,而实际上售出了两张,这样就可能导致同一个座位售出两张车票,数据库出现了数据的不一致性错误。
并发操作导致数据库出现数据不一致性的问题,如下表所示。事务 T1 将数据对象,即火车票的总数 A 进行了修改,变为 49,而事务 T2 在 T1 修改 A 之前读取的 A 的值仍然
是 50,T2 将此值修改为 49 后写回数据库并覆盖了 T1 事务对 A 的修改,此时,A 的值为49,就会出现这种情况:卖出两张车票后车票总数应为 48,而数据库中车票的总数为 49,
显然出现了数据的不一致性错误。

封锁技术在一定程度上解决了数据库的并发事务处理过程中,并发操作给数据库带来的数据一致性问题,但同时产生了新的问题如活锁和死锁。
在处理并发事务的过程中,如果事务 T1 在数据对象 R 上加锁,事务 T2 又请求为数据 对象 R 加锁,则 T2 必须等待 T1 释放加在 R 上的锁。如果事务 T3 也请求为 R 加锁,当 T1 释放了 R 上的锁之后系统首先响应 T3 的请求,则允许 T3 对 R 加锁,此时 T2 仍需等 待 T3 释放加在 R 上的锁。然后事务 T4 又请求封锁 R,当 T3 释放了 R 上的封锁之后系统 又响应了 T4 的请求……T2 有可能永远等待而无法为 R 加锁,这就是活锁。
活锁也称饿死,由于事务永远得不到封锁而导致。避免活锁可以采用先来先服务的策略。当多个事务请求封锁同一个数据对象时,可按照请求封锁的先后次序对事务排队,数据对象上的锁一旦释放就批准申请队列的第一个事务获得封锁。
|
T1 |
T2 |
T3 |
T4 |
|
LOCK (R) …… …… UNLOCK (R)
|
LOCK (R) 等待 等待 等待 等待
|
LOCK (R) 等待 LOCK (R) …… UNLOCK (R)
|
LOCK (R) 等待 等待 等待 LOCK (R) ……
|
如果事务 T1 对数据对象 R1 进行封锁,T2 对数据对象 R2 进行封锁,然后 T1 又请求对 R2 进行封锁,由于 T2 已封锁了 R2,则 T1 必须等待 T2 释放 R2 上的锁。接着 T2 又申请对 R1 进行封锁,由于 T1 已封锁 R1,因此,T2 也只能等待 T1 释放 R1 上的锁。这样就出现了事务 T1 等待另一个事务 T2 释放相关数据对象上的锁,而 T2 又在等待 T1 释放相关对象上的锁,T1 和 T2 两个事务由于相互等待对方释放数据对象上的锁而永远不能继续执行,这样就出现了死锁。
死锁(Dead Lock):系统中有两个或两个以上的事务都处于等待状态,并且每个事务都在等待其中另一个事务释放封锁,这样才能继续执行下去,结果造成任何一个事务都无法继续执行,这种现象称数据库系统进入了“死锁”(Dead Lock)状态
用例简单复现死锁产生
GBase模式下(会话1):
Create database if not exists testdb with buffered log; Database testdb; Create table if not exists a(c1 int,c2 int); Create table if not exists b(c1 int,c2 int); Insert into a values(1,1); Insert into a values(2,2); Insert into b values(1,1); Insert into b values(1,1); !sh /tmp/rd129/onmode_I143_rd129 Set isolation to repeatable read; Set lock mode to wait; Begin; Select *from b; --读b表,对b表加上S锁 !echo “sql start sleep 5” !sleep 15 !echo “sql sleep 5 done” Update a set c1=6 where c2=2; -更新a表,想对a表加上X锁 Commit; Close database; !cat /tmp/rd129/out.log Drop database testdb; onmode_I143_rd129内容如下(会话2): Onmode -I 143 ( Dbaccess -e-m testdb - <<! Set isolation to repeatable read; Set lock mode to wait; Begin; Select * from a; --读a表,对a表加上S锁 !echo “sql start sleep 5” !sleep 10 !echo “sql sleep 5 done” Update b set c1=6 where c2=2; --更新b表,想对b表加上X锁 Commit; ! ) >/tmp/rd129/out.log 2>&1 &
那么两个会话分别在同一个库中,对a表和b表加上共享锁S,当想进行更新时,会话1在等待会话2释放a的S锁,而会话2在等待会话1释放b的S锁,从而导致死锁产生。
那么在oracle模式下,该用例却不能产生死锁。
因为在GBase模式下,开启事务后,可以保证两个会话在执行更新后才提交保证两个会话同时进行。
而在oracle模式下,只能开启多语句模式,DML语句会自动开启事务,通过commit/rollback结束事务,DDL会提交事务。从而导致两个会话可能无法同时进行,因此并行变成串行,导致死锁无法产生。
南大通用GBase 8s数据库的事务处理能力和并发控制机制,为企业提供了一个可靠、高效和安全的数据处理平台。无论是金融交易还是在线事务处理,GBase 8s都能确保数据的完整性和一致性,满足企业对数据库系统的要求。
原文链接:
https://www.gbase.cn/community/post/4582
更多精彩内容尽在南大通用
GBase技术社区,南大通用致力于成为用户最信赖的
数据库产品供应商。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69979120/viewspace-3074172/ ,如需转载,请注明出处,否则将追究法律责任。