[TOC] # SAVEPOINT ## 描述 SAVEPOINT语句用来实现事务的部分回滚。 ## 格式 1. 创建savepoint: ~~~ SAVEPOINT spname ~~~ 2. 回滚到savepoint: ~~~ ROLLBACK [WORK] to [SAVEPOINT] spname ~~~ 3. 删除savepoint: ~~~ RELEASE SAVEPOINT spname ~~~ ## 参数说明 * spname:指定savepoint的名称。savepoint是事务范围内唯一的,一个savepoint会覆盖前一个同名的savepoint。创建savepoint后可以将事务回滚到指定savepoint,也可以使用`ROLLBACK`语句回滚整个事务。 ## 举例 假设一个事务执行了如下语句: <table data-tag="table" id="table-cu2-j66-c6j" class="table"><colgroup width="240" span="1" data-tag="col" id="col-mbz-7t7-qs5" colwidth="1*" colnum="1" colname="col1" style="width:33.33333333333333%" class="col"></colgroup><colgroup width="240" span="1" data-tag="col" id="col-o15-nnw-ajq" colwidth="1*" colnum="2" colname="col2" style="width:33.33333333333333%" class="col"></colgroup><colgroup width="240" span="1" data-tag="col" id="col-23x-0ey-e2i" colwidth="1*" colnum="3" colname="col3" style="width:33.33333333333333%" class="col"></colgroup><thead id="thead-84c-2rz-bxl" class="thead"><tr id="tr-3ha-toc-j6z"><th id="td-eo5-czk-mc4"><p id="p-tes-ixt-0xs"><b>sql_no</b></p></th><th id="td-i2t-e7l-2qg"><p id="p-9oh-9uf-ryc"><b>语句</b></p></th><th id="td-qmw-6g9-zvb"><p id="p-mj7-4ef-ero"><b>分区</b></p></th></tr></thead><tbody data-tag="tbody" id="tbody-hux-o1a-tgh" class="tbody"><tr data-tag="tr" id="tr-zr3-md8-d97" class="tr"><td data-tag="td" id="td-pxx-sbg-ae9" class="td"><p data-tag="p" id="p-pys-iqo-8o1" class="p">1</p></td><td data-tag="td" id="td-e5m-fka-cxr" class="td"><p data-tag="p" id="p-8a2-ai7-te3" class="p">update...</p></td><td data-tag="td" id="td-s52-hkw-7nn" class="td"><p data-tag="p" id="p-0pc-xii-o5y" class="p">p1, p4</p></td></tr><tr data-tag="tr" id="tr-jhi-lsz-o7g" class="tr"><td data-tag="td" id="td-cix-px0-cg2" class="td"><p data-tag="p" id="p-qc5-2p6-orw" class="p"></p></td><td data-tag="td" id="td-th4-g6s-19s" class="td"><p data-tag="p" id="p-fyq-9nf-1tv" class="p">savepoint sp1</p></td><td data-tag="td" id="td-15d-m9a-4pv" class="td"><p data-tag="p" id="p-4n9-qzk-ffw" class="p"></p></td></tr><tr data-tag="tr" id="tr-qlv-9zd-9ni" class="tr"><td data-tag="td" id="td-6uv-aeg-xuk" class="td"><p data-tag="p" id="p-0qa-ck8-pnu" class="p">2</p></td><td data-tag="td" id="td-vq6-92g-0k8" class="td"><p data-tag="p" id="p-4hn-l80-7hh" class="p">update...</p></td><td data-tag="td" id="td-hfn-0wx-ubh" class="td"><p data-tag="p" id="p-73x-f09-n78" class="p">p2, p4</p></td></tr><tr data-tag="tr" id="tr-5xr-1rh-82s" class="tr"><td data-tag="td" id="td-hvo-27h-ys9" class="td"><p data-tag="p" id="p-w6f-trs-phl" class="p">3</p></td><td data-tag="td" id="td-yn8-snn-w67" class="td"><p data-tag="p" id="p-l0s-hq2-zdx" class="p">update...</p></td><td data-tag="td" id="td-rp7-87k-c76" class="td"><p data-tag="p" id="p-9di-r08-7rv" class="p">p3, p5</p></td></tr><tr data-tag="tr" id="tr-axj-vj5-1c7" class="tr"><td data-tag="td" id="td-g5u-u4v-mog" class="td"><p data-tag="p" id="p-ot8-4p3-48t" class="p"></p></td><td data-tag="td" id="td-b2a-bwe-kvd" class="td"><p data-tag="p" id="p-eyn-2k3-xk4" class="p">savepoint sp2</p></td><td data-tag="td" id="td-j2e-ghs-hi2" class="td"><p data-tag="p" id="p-6v1-4vp-1ag" class="p"></p></td></tr><tr data-tag="tr" id="tr-edg-fwf-twf" class="tr"><td data-tag="td" id="td-r3s-0o9-uff" class="td"><p data-tag="p" id="p-i32-8q1-mmt" class="p">4</p></td><td data-tag="td" id="td-iek-0iu-b8d" class="td"><p data-tag="p" id="p-tqc-dlg-v5u" class="p">update...</p></td><td data-tag="td" id="td-qvs-0jb-2g5" class="td"><p data-tag="p" id="p-a2x-nqr-sre" class="p">p1, p3, p6</p></td></tr><tr data-tag="tr" id="tr-nma-e5p-ty8" class="tr"><td data-tag="td" id="td-a01-bam-q8v" class="td"><p data-tag="p" id="p-9ud-wki-x0o" class="p">5</p></td><td data-tag="td" id="td-lu6-ot3-q88" class="td"><p data-tag="p" id="p-meq-2qz-8ka" class="p">update...</p></td><td data-tag="td" id="td-59r-1x4-i8g" class="td"><p data-tag="p" id="p-f1z-oeo-06f" class="p">p1, p5</p></td></tr><tr data-tag="tr" id="tr-2ql-fql-15n" class="tr"><td data-tag="td" id="td-f40-lmv-0su" class="td"><p data-tag="p" id="p-odx-2kx-3g0" class="p"></p></td><td data-tag="td" id="td-ov3-5gj-4oo" class="td"><p data-tag="p" id="p-jkr-vj8-50e" class="p">savepoint sp3</p></td><td data-tag="td" id="td-b9h-jex-0w5" class="td"><p data-tag="p" id="p-zsm-4wq-xef" class="p"></p></td></tr><tr data-tag="tr" id="tr-mbh-9pn-jad" class="tr"><td data-tag="td" id="td-duc-pqu-tjq" class="td"><p data-tag="p" id="p-ftc-ik1-x92" class="p">6</p></td><td data-tag="td" id="td-fuq-ihb-cgh" class="td"><p data-tag="p" id="p-ohc-jt3-kuj" class="p">select...</p></td><td data-tag="td" id="td-wim-hla-e34" class="td"><p data-tag="p" id="p-5vc-q97-2js" class="p"></p></td></tr><tr data-tag="tr" id="tr-tsl-yqt-t8u" class="tr"><td data-tag="td" id="td-iwf-jj6-pds" class="td"><p data-tag="p" id="p-hqu-zf0-6iv" class="p">7</p></td><td data-tag="td" id="td-lco-uue-f2t" class="td"><p data-tag="p" id="p-auy-45x-zr4" class="p">update...</p></td><td data-tag="td" id="td-cbq-vfv-3ec" class="td"><p data-tag="p" id="p-12c-yqx-mkz" class="p">p5, p6</p></td></tr><tr data-tag="tr" id="tr-kkq-v3v-g2k" class="tr"><td data-tag="td" id="td-v1o-r65-szm" class="td"><p data-tag="p" id="p-1i1-m92-4s4" class="p"></p></td><td data-tag="td" id="td-19o-zoo-qlv" class="td"><p data-tag="p" id="p-4is-ayu-d6m" class="p">savepoint sp4</p></td><td data-tag="td" id="td-mtl-ucq-1hk" class="td"><p data-tag="p" id="p-fst-2ro-zh0" class="p"></p></td></tr></tbody></table> #### 记录savepoint 用户在提交事务之前可以创建savepoint,需要根据savepoint创建的顺序,将事务的savepoint串成链表。以上事务包含了7条sql和4个savepoint,记录savepoint的链表如下图所示,其中每个节点记录了的映射关系: ![](https://img.kancloud.cn/00/62/0062841035d0bdc013db127b76fb5497_525x53.png) #### 事务参与者列表 事务为了支持回滚某条sql之后的所有修改,需要将每条语句涉及的参与者以及对应的sql\_no记录下来,以上事务执行了7条sql,涉及p1~p6共6个partition: ![](https://img.kancloud.cn/ca/33/ca33c07be6432de7de9861faf05069c3_448x67.png) #### savepoint回滚过程 1. 根据savepoint链表查询spname对应的sql\_no 假设用户执行`ROLLBACK to SAVEPOINT sp2`,根据savepoint链表查询到sp2对应的sql\_no为3。 2. 根据事务参与者列表查询sql\_no对应的partition 根据事务参与者列表查询到sql\_no大于3的语句操作的分区涉及p1、p3、p5、p6。 3. 回滚分区数据 根据第2步查询到的分区,调度程序向这些分区发起回滚请求,回滚当前事务在这些分区上sp2之后的所有修改。其中p1、p3、p5上关于本事务的部分修改被回滚掉,p6上关于本事务的所有修改都被回滚掉。 4. 更新事务参与者列表信息 修改事务参与者列表,将sql\_no大于3的操作信息从事务参与者列表中删除,由于p6上的所有修改都被回滚掉,因此p6可以从参与者列表中删除。 ![](https://img.kancloud.cn/c4/0c/c40cef0b892090ee41edbd9bae173aca_448x67.png) 5. 删除无效的savepoint 用户执行`ROLLBACK to SAVEPOINT sp2`成功后,系统会删除sp3和sp4的savepoint,不允许再回滚到sp3和sp4。 ![](https://img.kancloud.cn/c8/29/c8296ae0a3e99f6b393b678c1ae41cbc_245x53.png)