达梦事物特性及MVCC

一 支持的事物隔离

达梦几种隔离级别都支持,默认的隔离级别是读已提交。

|-------------------|------------|
| 隔离级别\数据库 | 达梦 |
| 未提交读 | 支持 |
| 已提交读 | 支持(默认) |
| 可重复读 | 支持 |
| 可串行化 | 支持 |

|--------------------|------------|---------------|------------|
| 隔离级别 \ 解决 | 脏读 | 不可重复读 | 幻读 |
| 未提交读 | 可能 | 可能 | 可能 |
| 已提交读 | 不可能 | 可能 | 可能 |
| 可重复读 | 不可能 | 不可能 | 可能 |
| 可串行化 | 不可能 | 不可能 | 不可能 |

二 相关验证

2.1 读未提交

查看当前的隔离级别

|------------------------------|
| select isolation from v$trx; |

1表示为默认的读已提交,0为读未提交,3为可重复读与可串行读。

查看当前T1表中的数据

新开会话,修改当前会话隔离级别为读未提交。

|---------------------------------------------------------|
| SQL> SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |

在另一个会话中插入一行新数据,不用提交,回到会话1中查看数据

会话1:

此时的会话1能够查到会话2没有提交的数据。

2.2 读已提交

读已提交是达梦的默认隔离级别,只能查询到其他事物提交之后的数据。

新开一个会话,查看当前的隔离级别。

|------------------------------|
| select isolation from v$trx; |

构建T2表,插入一行数据

新开一个会话,插入一行数据不提交。

回到会话1查看是查询不到新插入的数据的。

在会话2中提交后返回会话1查看

会话1:能看到添加的数据能够查看到了。

2.3 可重复读

构建新表T3,并插入新的数据。

新开一个会话并设置隔离为可重复读。

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| SQL> SET TRANSACTION ISOLATION LEVEL repeatable read ; 操作已执行 已用时间: 7.290(毫秒). 执行号:1501. SQL> SELECT isolation FROM V$TRX; 行号 ISOLATION ---------- ----------- 1 3 |

在当前会话中修改一行数据的值但是不提交。

此时会话1已经正常修改。

新开一个会话2并设置隔离为可重复读。

在会话2中查看T3表的数据,能看到还是修改之前的。

此时在会话1中提交数据,返回会话2再次查看。

会话2看到的还是修改之前的。

其他会话修改并提交的数据不会影响当前会话的读取结果。这保证了在同一个事务中多次读取同一数据时,能够得到相同的结果。

2.4 可串行读

验证过程与结果跟可重复度类似,可串行读要求消除不可重复读取和幻像读现象,本身查询不会增加任何代价,但是当串行化事物更新或者删除数据时,其他事物会被当前事物阻塞,只有当串行化事物提交或者回滚后才会释放,报错:"串行化事物被打断"。

创建新表,插入数据。

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| SQL> create table t4 (id number(10),name char(10)); 操作已执行 已用时间: 94.853(毫秒). 执行号:2101. SQL> insert into t4 values(1,'AA'); 影响行数 1 已用时间: 3.777(毫秒). 执行号:2102. SQL> commit; 操作已执行 已用时间: 2.794(毫秒). 执行号:2103. SQL> select * from t4; 行号 ID NAME ---------- -- ---------- 1 1 AA 已用时间: 2.977(毫秒). 执行号:2104. |

新开会话1,设置隔离级别为可串行读

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| SQL> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 操作已执行 已用时间: 1.634(毫秒). 执行号:2301. SQL> SELECT isolation FROM V$TRX; 行号 ISOLATION ---------- ----------- 1 3 已用时间: 0.197(毫秒). 执行号:2302. |

更新新表数据但是不提交

新开一个会话2设置隔离级别为可串行读。查看T4表数据

此时还是修改之前的数据

在会话1中提交

会话2查看还是修改之前的数据。

此时在会话1中再更新一下数据不要提交。

|-----------------------------------------------------------------------------|
| SQL> update t4 set name='CC' where id=1; 影响行数 1 已用时间: 3.637(毫秒). 执行号:3006. |

在会话2中也修改此行发现会话卡住。

在会话1中commit或者rollback之后这边会话才能结束。

此时会话2出现串行化事物被打断

MVCC机制

达梦数据库为用户提供了两种MVCC模式,通过参数TRX_VIEW_MODE控制:

1.基于回滚记录的MVCC(TRX_VIEW_MODE=0):

数据行包含事务TID和版本指针RPTR,使得记录间单向连接,形成链式版本结构。

事务根据当前活动事务的视图,依据链式版本结构,构成可见的记录集合\[\]。

2.基于时间戳的MVCC(TRX_VIEW_MODE=1):

全局维护一个大数组CMTARR(Commit Array),长度由参数TRX_CMTARR_SIZE控制(单位:百万)。事务在启动时获取一个时间戳SNAP_CMTSEQ,提交时将CMTARR中对应位置(事务号)的值设置为当前时间。数据版本的可见性通过比较SNAP_CMTSEQ和CMTSEQ来判断:如果SNAP_CMTSEQ >= CMTSEQ,则数据版本可见;否则不可见。

默认为基于时间戳的MVCC。

1、进行多版本读时,这个视图的使用方式是这样的:

在形成活动事务视图TRX_VIEW时,一个事务还收集当前最下活动事务号MIN_ACTIVE_ID,以及全局下一个事务号NEXT_ID。这样,一个事务在读一条记录时,就可以进行如下的比对:

|---------------------|-------|
| 记录事务ID大于(等于)下一个事务ID | 记录不可见 |
| 记录事务ID等于自身事务ID | 记录可见 |
| 记录事务ID小于当前最小已激活事务ID | 记录可见 |
| 记录事务ID不在事务视图中 | 记录可见 |
| 记录事务ID在事务视图中 | 记录不可见 |

对于可见的记录,则取这条记录为最终版本;对于不可见的记录,则通过链式版本继续向这条记录的过往版本进行上述的比对,直到找到可见的版本(或不取这条记录)。

2、DM数据库提供给用户第二种MVCC方式,也是当前版本DM数据库的默认MVCC方式,即基于时间戳的MVCC。

这种MVCC的实现方式是,全局只维护一个大数组CMTARR(长度一般在千万级);DM数据库令事务在启动时,将这个数组中对应位置(事务号)上的数据CMTSEQ置为0,而在事务提交时,则将这个位置上的数据CMTSEQ置为当前的时间。

这样的话,事务或SQL启动时,只需要获取一个当前的时间戳SNAP_CMTSEQ,再与记录ID在CMTARR对应位置上的时间戳比对,就可得出可见与否了。具体比对方式如下:

|------------------------|-----|
| SNAP_CMTSEQ >= CMTSEQ | 可见 |
| SNAP_CMTSEQ < CMTSEQ | 不可见 |

这个大数组的长度,可以由静态参数TRX_CMTARR_SIZE控制(单位:百万)。这个参数设置 越大,内存消耗越多;单位时间内事务完成数量大时,可将此参数值设大。

DM在这种MVCC策略下,对于"长事务",也有对应的处理方案。

所谓"长事务",就是事务号<下一个事务号-(数组长度/2)的事务,即当前的下个事务(即全局最新的事务)与这个长事务间隔超过了CMTARR数组长度的一半,也就是执行时间超长,以至于在其执行期间由大量新事务启动的事务。

相关推荐
小马同学-1 小时前
MySQL主从复制和读写分离
数据库·mysql
谢亮_vipxieliang1 小时前
Spring 事务失效的常见场景
java·开发语言·数据库·spring boot
geovindu2 小时前
sql: JSON and XML Data Handling in SQL using sql server 2025
大数据·数据库·sqlserver·数据库开发·数据库架构
亚川楼宇自控系统数据中心厂家2 小时前
实验室智能化管理系统|人环物智一体化管控平台
运维
IT大白鼠3 小时前
图数据库系列 · 第 02 篇——架构拆解:原生图存储到因果集群
数据库·架构·nosql
羔羊++3 小时前
18_实验十七_其他命令与自定义启动变量
linux
EatFan3 小时前
从“框架混战“到“运行时收敛“:2026 年 AI Agent 开发框架的三条路线之争
java·数据库·人工智能·多智能体·ai agent·mcp·agent 框架
小蒜学长3 小时前
基于SpringBoot的佳新超市管理系统设计与实现系统(代码+数据库+LW)
java·数据库·spring boot·后端·佳新超市管理系统
zmsup4 小时前
Agent 上下文调优:结合 OpsArk 运维智能体,设计模型每一步真正需要的信息
运维·agent·上下文压缩·运维智能体·上下文调优