看了一下OpenGauss的文档,截止目前,支持Read Committed和Repeatable Read隔离级别。
MOT不支持MVCC,它的多版本控制原理,简单说,是把要读写的数据从全局内存复制到,为连接分配的局部内存,insert或update先在局部内存做,commit时再复制回全局内存,此时先做有效性检查,如冲突就取消整个事务。
对MOT的乐观并发控制(OCC)原理做如下猜测:
Read Committed级别时,本事务读取A,如果其它事务修改A提交后,本事务再次读取A,是从全局内存读取,与第一次读取不同。
Repeatable Read级别时,本事务读取A,其它事务修改A提交后,本事务再次读取A,是从局部内存读取,与第一次读取相同,局部内存的值就相当于多版本。
不过,MOT的Repeatable Read级别,行为和磁盘表并不一样,例如:
-- 设置Repeatable Read隔离级别
set default_transaction_isolation to 'repeatable read';
begin;
-- emp2mot是内存表
select * from emp2mot;
-- 第一点不同:如果此时,其它事务向emp2mot插入或删除记录,并提交,第二次查询是可以看到的,而磁盘表是看不到的;其他事物update并提交记录,第二次查询看到的,仍然是之前的值,这一点与磁盘表相同。
select * from emp2mot;
commit;
WARNING: AbortTransaction while in COMMIT state
ERROR: Commit: could not serialize access due to concurrent update(0)
-- 第二点不同:本事务运行期间,查询的记录,如果被其它事务修改并提交了,那本事务提交时就会失败。
猜测Repeatable Read级别下,select就是select for update,所有select出来的读集合也是写集合。
从此现象看,OpenGauss的Repeatable Read隔离级别意义并不大。
在做转账业务时,数据库也不必使用Repeatable Read,可以使用Read Committed,但是在业务端,读取需要加减操作的记录时,要用select for update,以便实现这一记录的可重复读,与使用Repeatable Read的效果是一样的,可能整体的并发性更好(没深入研究)。
我猜其它数据库做转账业务时,也是使用Read Committed,然后应用程序使用select for update读取要操作的账户记录。
目前OpenGauss不支持在一个事务中同时操作磁盘表和MOT表,也不支持两者的JOIN,应该就是因为两种表并发控制的算法不同。
-----------------------------------------2023/1/12 更新---------------------------------------
3.1.1版本,官方宣称支持MVCC,支持MOT表和磁盘表JOIN。
测试了一下:
1、使用Repeatable Read隔离级别的事务TX,第一次select表t1,然后其它事务插入、删除、更新t1的记录,TX第二次select是看不到改变的。(第一点与磁盘表现象相同了)
2、本事务运行期间(无论何种隔离级别),查询的记录,如果被其它事务修改并提交了,那本事务提交时不会失败。(第二点与磁盘表现象相同了)
3、确实支持MOT表和磁盘表JOIN