保存点

在MySQL中, 保存点SAVEPOINT属于事务控制处理部分。利用SAVEPOINT可以回滚指定部分事务,从而使事务处理更加灵活和精细。SAVEPOINT相关的SQL语句如下

SAVEPOINT identifier

设置SAVEPOINT。如果重复设置同名savepoint,新的会覆盖老的.

RELEASE SAVEPOINT identifier

释放SAVEPOINT。

ROLLBACK [WORK] TO [SAVEPOINT] identifier

回滚到指定的SAVEPOINT。

InnoDB内部实现

保存点跟事务有关,因此我们这里只讨论事务引擎InnoDB的savepoint实现。

首先看server层保存点结构:

struct st_savepoint {
struct st_savepoint *prev;
char *name; /* 名字 */
uint length;
Ha_trx_info *ha_list; /* 设置savepoint时已注册的插件 */
/** State of metadata locks before this savepoint was set. */
MDL_savepoint mdl_savepoint;
};

InnoDB层保存点结构:

保存点结构:
struct trx_named_savept_t{
char* name; /*!< savepoint name */
trx_savept_t savept; /*!< the undo number corresponding to
the savepoint */
ib_int64_t mysql_binlog_cache_pos;
/*!< the MySQL binlog cache position
corresponding to this savepoint, not
defined if the MySQL binlogging is not
enabled */
UT_LIST_NODE_T(trx_named_savept_t)
trx_savepoints; /*!< the list of savepoints of a
transaction */
}; 链表存储事务上的所有保存点:
trx_t
{
UT_LIST_BASE_NODE_T(trx_named_savept_t)
trx_savepoints;
…….
} 保存点最重要的信息,事务回滚日志的序号:
struct trx_savept_t{
undo_no_t least_undo_no; /*!< least undo number to undo */
};

SAVEPOINT与UNDO日志

事务回滚通过回滚UNDO日志来实现,同样,回滚至保存点也是通过应用UNDO日志来实现。

InnoDB事务在每次修改操作时都会记录UNDO日志,参见函数trx_undo_report_row_operation,每次操作都会记录UNDO日志序号记为undo_no,每次操作undo_no都会递增。回滚只需要反向应用UNDO日志即可。 SAVEPOINT与undo_no是一一对应的。

create table t1(c1 int primary key);
begin;
insert into t1 values(1);
savepoint a;
insert into t1 values(2);
savepoint b;
insert into t1 values(3);
rollback to savepoint a;
commit;

SAVEPOINT与BINLOG

InnoDB开启binlog的情况下,savepoint回滚的那段操作不应记录binlog. 我们知道,事务执行过程中产生的binlog先写入cache中,提交时再将cache中的数据写binlog文件中。 然而,savepoint回滚时,binlog还在cache中,那么被回滚的那段操作的binlog需要从cache中清理掉。

设置savepoint时,记录binlog在cache中起始位置。

trans_savepoint
->ha_savepoint
->binlog_savepoint_set
->binlog_trans_log_savepos

回滚至savepoint时,从保存的起始位置清理cache

trans_rollback_to_savepoint
->ha_rollback_to_savepoint
->binlog_savepoint_rollback
->binlog_trx_cache_data::restore_savepoint
->binlog_cache_data::truncate
->reinit_io_cache

SAVEPOINT与锁

回滚保存点以后,此保存点以后的保存点都会释放,但此保存点以后InnoDB层操作加的锁不会释放。这里不释放锁,是为了不破坏两阶段锁协议,减少死锁的发生。

而对于MDL(metadate lock)锁,在binlog关闭的情况下可以提前释放。 而binlog开启的情况下,需考虑如下情况:

  1. 如果操作的仅是InnoDB表且InnoDB层没有加锁,则MDL锁可以释放,否则,不能释放。 InnoDB层持有锁,如果释放MDL可能出现死锁。考虑如下情况: trx 1: rollback to savepoint xxx; InnoDB层持有t1的行锁,释放t1的MDL trx 2: 操作t1; 持有t1的MDL, 等待t1行锁 trx 1: 再次操作t1; 等待t1的MDL锁,从而构成死锁。

  2. 如果操作中有非事务引擎,则不能释放MDL锁。 如果是非事务引擎,例如t1为MyiSAM表。 ... begin; insert into t1 values(1); savepoint a; insert into t1 values(2); rollback to savepoint a; commit; ... savepoint和rollback to savepoint之间的sql都会写入binlog. 如果提前释放MDL,其他会话drop table t1可以成功,这样会导致应用binlog时,执行insert into t1 values(2);会找不到表t1。

SAVEPOINT作用域

官方文档 中,store function和trigger会重新开启新的savepoint作用域, store function和trigger完成后老的savepoint作用域重新可用。

A new savepoint level is created when a stored function is invoked or a trigger is activated. The savepoints on previous levels become unavailable and thus do not conflict with savepoints on the new level. When the function or trigger terminates, any savepoints it created are released and the previous savepoint level is restored.

delimiter //
drop procedure if exists p1//
create procedure p1()
begin
release savepoint a;
end//
delimiter ; begin;
savepoint a;
call p1();
rollback to savepoint a;
ERROR 1305 (42000): SAVEPOINT a does not exist

从结果来看与官方文档描述并不一致。

实际从代码中上看,stored function和trigger并没有开启独立的事务,而是与调用着共用同一事务。savepoint都在同一事务的链表中,因此store function和trigger中的savepoint作用域和调用者相同。

官方对savepoint的实现并不彻底。

匿名SAVEPOINT

实际上,InnoDB事务中每个语句执行前都会记录一个匿名savepoint;如果当前语句执行失败,不会回滚整个事务,而是利用这个匿名savepoint回滚失败的语句。

struct trx_t{
trx_savept_t last_sql_stat_start; //匿名savepoint
......

savepoint原理的更多相关文章

  1. [Flink原理介绍第四篇】:Flink的Checkpoint和Savepoint介绍

    原文:https://blog.csdn.net/hxcaifly/article/details/84673292 https://blog.csdn.net/zero__007/article/d ...

  2. mysqldump和xtrabackup备份原理实现说明

    背景: MySQL数据库备份分为逻辑备份和物理备份两大类,犹豫到底用那种备份方式的时候先了解下它们的差异: 逻辑备份的特点是:直接生成SQL语句,在恢复的时候执行备份的SQL语句实现数据库数据的重现. ...

  3. mysqldump的实现原理

    对于MySQL的备份,可分为以下两种: 1. 冷备 2. 热备 其中,冷备,顾名思义,就是将数据库关掉,利用操作系统命令拷贝数据库相关文件.而热备指的是在线热备,即在不关闭数据库的情况下,对数据库进行 ...

  4. 深入理解 Spring 事务原理

    本文由码农网 – 吴极心原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 一.事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供 ...

  5. 深入理解 Spring 事务原理【转】

    本文转自码农网 – 吴极心原创  连接地址:http://www.codeceo.com/article/spring-transactions.html 一.事务的基本原理 Spring事务的本质其 ...

  6. MySQL事务原理&实战【官方精译】

    事务隔离级别 事务隔离是数据库处理的基础之一.隔离是I中的首字母 ACID ; 隔离级别是在多个事务同时进行更改和执行查询时,对结果的性能和可靠性,一致性和可重复性之间的平衡进行微调的设置. Inno ...

  7. Flink 集群运行原理兼部署及Yarn运行模式深入剖析

    1 Flink的前世今生(生态很重要) 原文:https://blog.csdn.net/shenshouniu/article/details/84439459 很多人可能都是在 2015 年才听到 ...

  8. java事务 深入Java事务的原理与应用

    一.什么是JAVA事务 通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性 (iso ...

  9. spring事务-说说Propagation及其实现原理

    前言 spring目前已是java开发的一个事实标准,这得益于它的便利.功能齐全.容易上手等特性.在开发过程当中,操作DB是非常常见的操作,而涉及到db,就会涉及到事务.事务在平时的开发过程当中,就算 ...

随机推荐

  1. 清除oracle中的缓存(具体细节未知, 慎用)

    oracle中的缓存主要是指SGA中的:1.share pool2.database buffer cache清空命令如下:首先要登录到sqlplus命令下,输入如下命令即可:SQL> alte ...

  2. mongo基本操作

    创建数据库文件的存放位置,比如d:/mongodb/data/db.启动mongodb服务之前需要必须创建数据库文件的存放文件夹,否则命令不会自动创建,而且不能启动成功. 打开cmd(windows键 ...

  3. android杂记

    1.ArrayAdapter requires the resource ID to be a TextView问题 listView.setAdapter(new ArrayAdapter<S ...

  4. Mac下U盘安装系统“未验证的错误”

    bash下 输入下面命令: date 1220141012015.30

  5. Ajax Step By Step2

    第二.[$.get()和$.post()方法] .load()方法是局部方法(有需要父$),因为他需要一个包含元素的 jQuery 对象作为前缀.而$.get()和 $.post()是全局方法,无须指 ...

  6. Sublime Text 安装Emmet

    1.简单的安装方法 从菜单 View - Show Console 或者 ctrl + ~ 快捷键,调出 console.将以下 Python 代码粘贴进去并 enter 执行,不出意外即完成安装.以 ...

  7. 使用.NET读取exchange邮件

    公司有个第3方的系统,不能操作源码修改错误捕获,但是错误会发一个邮件出来,里面包含了主要的信息.于是想从邮件下手,提取需要的数据 开始考虑使用的是exchange service,主要参考http:/ ...

  8. java线程池初步理解

    多线程基础准备 进程:程序的执行过程,持有资源和线程 线程:是系统中最小的执行单元,同一个进程可以有多个线程,线程共享进程资源 线程交互(同步synchronized):包括互斥和协作,互斥通过对象锁 ...

  9. Unity4升级Unity5后Image Effects问题

    Assets\Editor\Image Effects\CameraMotionBlurEditor.js 会出现Ambiguous reference 'preview'错误提示,解决方法 查找pr ...

  10. C# 部分语法总结(入门经典)

    class Program { static void Main(string[] args) { init(); System.Console.ReadKey(); } #region 接口 /// ...