10.3 写事务
写事务,包括更新(UPDATE)、插入(INSERT)、删除(DELETE)、替换(REPLACE,插入或者更新,如果行不存在则插入新行;否则,更新已有行),由MergeServer解析后生成物理执行计划,这个物理执行计划最终将发给UpdateServer执行。写事务可能需要读取基线数据,用于判断更新或者插入的数据行是否存在,判断某个条件是否满足,等等,这些基线数据也会由MergeServer传给UpdateServer。
10.3.1 写事务执行流程
大部分写事务都是针对单行的操作,如果单行事务不带其他条件:
●REPLACE:REPLACE事务不关心写入行是否已经存在,因此,MergeServer直接将修改操作发送给UpdateServer执行。
●INSERT:MergeServer首先读取ChunkServer中的基线数据,并将基线数据中行是否存在信息发送给UpdateServer,UpdateServer接着查看增量数据中行是否被删除或者有新的修改操作,融合基线数据和增量数据后,如果行不存在,则执行插入操作;否则,返回行已存在错误。
●UPDATE:与INSERT事务执行步骤类似,不同点在于,行已存在则执行更新操作;否则,什么也不做。
●DELETE:与UPDATE事务执行步骤类似。如果行已存在则执行删除操作;否则,什么也不做。
如果单行写事务带有其他条件:
●UPDATE:如果UPDATE事务带有其他条件,那么,MergeServer除了从基线数据中读取行是否存在,还需要读取用于条件判断的基线数据,并传给UpdateServer。UpdateServer融合基线数据和增量数据后,将会执行条件判断,如果行存在且判断条件成立则执行更新操作。否则,返回行已存在或者条件不成立错误。
●DELETE:与UPDATE事务执行步骤类似。
例10-6 有一张表格item(user_id,item_id,item_status,item_name),其中,<user_id,item_id>为联合主键。
MergeServer首先解析图10-6的SQL语句产生执行计划,确定待修改行的主键为<1,2>,接着,请求主键<1,2>所在的ChunkServer,获取基线数据中行是否存在,最后,将SQL执行计划和基线数据中行是否存在一起发送给UpdateServer。UpdateServer融合基线数据和增量数据,如果行已存在且未被删除,UPDATE和DELETE语句执行成功,INSERT语句执行返回“行已存在”;如果行不存在或者最后被删除,INSERT语句执行成功,UPDATE和DELETE语句返回“行不存在”。
图 10-6 单行写事务(不带条件)
图10-7中的UPDATE和DELETE语句还带有item_name="item1"的条件,MergeServer除了请求ChunkServer获取基线数据中行是否存在,还需要获取item_name的内容,并将这些信息一起发送给UpdateServer。UpdateServer融合基线数据和增量数据,判断最终结果中行是否存在,以及item_name的内容是否为"item1",只有两个条件同时成立,UPDATE和DELETE语句才能够执行成功;否则,返回“行不存在或者item_name列的内容不符合预期”。
图 10-7 单行写事务(带条件)
当然,并不是所有的写事务都这么简单。复杂的写事务可能需要修改多行数据,事务执行过程也可能比较复杂。
例10-7 有两张表格item(user_id,item_id,item_status,item_name)以及user(user_id,user_name)。其中,<user_id,item_id>为item表格的联合主键,user_id为user表格的主键。
图10-8的UPDATE语句可能会更新多行。MergeServer首先从ChunkServer获取编号为1的用户包含的全部item(可能包含多行),并传给UpdateServer。接着,UpdateServer融合基线数据和增量数据,更新每个存在且未被删除的item的item_status列。
图 10-8 复杂写事务举例
图10-8的DELETE语句更加复杂,执行时需要首先获取user_name为“张三”的用户的user_id,考虑到事务隔离级别,这里可能需要锁住user_name为“张三”的数据行(防止user_name被修改为其他值)甚至锁住整张user表(防止其他行的user_name修改为“张三”或者插入user_name为“张三”的新行)。接着,获取用户名为“张三”的所有用户的所有item,最后,删除这些item。这条语句执行的难点在于如何降低锁粒度以及锁占用时间,具体的做法请读者自行思考。