显式事务是指,用户在所执行的一条或多条SQL语句的前后,显式添加了开启事务START TRANSACTION语句和提交事务COMMIT语句。
隐式事务是指,用户在所执行的一条或多条SQL语句的前后,没有显式添加开启事务和提交事务的语句。在这种情况下,每一条SQL语句在开始执行时,openGauss内部都会为其开启一个事务,并且在该语句执行完成之后,自动提交该事务。
以一条SELECT语句和一条INSERT语句为例,简要描述显式事务和隐式事务在openGauss集群中的主要执行流程。
显式事务的SQL语句如下(假设表t只包含一个整数类型字段a,且为分布列):
START TRANSACTION;
SELECT * FROM t;
INSERT INTO t(a) VALUES (100);
COMMIT;
1)START TRANSACTION
该SQL语句只在CN上执行,CN显式开启一个事务,并将CN本地事务块状态机从空闲状态置为进行中状态,然后返回客户端,等待下一条SQL命令。
2)SELECT * FROM t
该SQL语句首先在CN上执行,由于openGauss分片采用一致性哈希算法,因此对于不带分布列上谓词条件的查询语句,CN需要将该SQL语句发送到所有DN实例上执行。对于每一个分片对应的DN实例,由于采用了显式事务,CN会先发送一条START TRANSACTION命令给该DN,让该DN显式开启事务(DN上的事务块状态机从空闲状态变为进行中状态),然后CN将SELECT语句发送给该DN。此后,CN在收到所有DN的查询结果之后,返回客户端,等待下一条SQL命令。
3)INSERT INTO t(a) VALUES (100)
该SQL语句首先在CN上执行,由于a为表t的分布列,因此CN可以根据被插入记录中a的具体取值,来决定应该由哪个数据分片对应的DN实例来执行实际的插入操作(这里假设该分片为DN1)。由于采用了显式事务,CN先发送一条START TRANSACTION命令给DN1,由于经过第(2)步DN1的事务块状态机已经处于进行中状态,因此对于该语句DN1并不会执行什么实际的操作,然后,CN将具体的INSERT语句发送给DN1,并等待DN1执行插入成功之后,返回客户端,等待下一条SQL命令。
4)COMMIT
该SQL语句首先在CN上执行,CN进入提交事务阶段后,将COMMIT语句发送给所有参与第(2)步和第(3)步的DN,让这些DN结束该事务,并将DN本地的事务块状态机从进行中状态置为空闲状态。CN在收到所有DN的事务提交结果之后,再将CN本地的事务块状态机从进行中状态置为空闲状态。然后,CN返回客户端,该事务执行完成。
上述操作的隐式事务语句如下(假设表t只包含一个整数类型字段a,且为分布列):
SELECT * FROM t;
INSERT INTO t(a) VALUES (1);
1)SELECT * FROM t
该SQL语句首先在CN上执行,CN隐式开启一个事务,将CN本地的事务块状态机从空闲状态置为开启状态(注意不同于显式事务中的进行中状态)。然后,CN需要将该语句发送到所有DN实例上执行。对于每一个分片对应的DN实例,由于采用了隐式事务且该语句为只读查询,CN直接将SELECT语句发送给该DN。
DN收到该SELECT语句之后,亦采用隐式事务:第一步,隐式开启事务,将DN本地的事务块状态机从空闲状态置为开启状态;第二步,执行该查询语句,将查询结果返回给CN;第三步,隐式提交事务,将DN本地的事务块状态机从开启状态置为空闲状态。
CN在收到所有DN的查询结果之后,返回客户端,并隐式提交事务,将CN本地的事务块状态机从开启状态置为空闲状态。
2)INSERT INTO t(a) VALUES (1)
该SQL语句首先在CN上执行,CN隐式开启一个事务,将CN本地的事务块状态机从空闲状态置为开启状态。然后,CN需要将该INSERT语句发送到目的分片的DN实例上执行(这里假设该分片为DN1)。
虽然该语句采用了隐式事务,但是由于该语句为写操作,因此在DN1上会采取显式事务:CN会先发送一条START TRANSACTION命令给DN1,让DN1显式开启事务(DN1上的事务块状态机从空闲状态变为进行中状态),然后CN将INSERT语句发送给DN1,DN1执行完成后,返回执行结果给CN。
CN收到执行结果之后,进入提交事务阶段。先发送COMMIT语句到DN1。DN1收到COMMIT语句后,进行显式提交,将DN1本地的事务块状态机从进行中状态置为空闲状态。CN在收到DN1的事务提交结果之后,本地再进行隐式提交事务,将CN本地的事务块状态机从开启状态置为空闲状态,返回客户端,该事务执行完成。
综上,对于CN来说,使用显式事务还是隐式事务,完全取决于用户输入的SQL语句;对于DN来说,只有当SQL为隐式只读事务时,才会使用隐式事务,当SQL为显式事务或者隐式写事务时,都会使用显式事务。




