PingCAP
  • 文档
  • 案例
  • 博客
  • 关于
  • 下载
PingCAP
  • 文档
  • 案例
  • 博客
  • 关于
  • 下载

Contact

  • 微信扫一扫
    微信ID:pingcap2015

English
文档
  • 关于 TiDB
    • TiDB 简介
    • TiDB 整体架构
    • TiDB 核心特性
  • TiDB 快速入门
    • 快速入门指南
    • SQL 基本操作
  • TiDB 用户文档
    • TiDB 数据库管理
      • TiDB 服务
      • TiDB 进程启动参数
      • TiDB 数据目录
      • TiDB 系统数据库
      • TiDB 系统变量
      • TiDB 专用系统变量和语法
      • TiDB 服务器日志文件
      • TiDB 访问权限管理
      • TiDB 用户账户管理
      • 使用加密连接
    • SQL 优化
      • 理解 TiDB 执行计划
      • 统计信息
    • 语言结构
      • 字面值
      • 数据库、表、索引、列和别名
      • 关键字和保留字
      • 用户变量
      • 表达式语法
      • 注释语法
    • 字符集和时区
      • 字符集支持
      • 字符集配置
      • 时区
    • 数据类型
      • 数值类型
      • 日期和时间类型
      • 字符串类型
      • JSON 数据类型
      • 枚举类型
      • 集合类型
      • 数据类型默认值
    • 函数和操作符
      • 函数和操作符概述
      • 表达式求值的类型转换
      • 操作符
      • 控制流程函数
      • 字符串函数
      • 数值函数与操作符
      • 日期和时间函数
      • 位函数和操作符
      • Cast 函数和操作符
      • 加密和压缩函数
      • 信息函数
      • JSON 函数
      • GROUP BY 聚合函数
      • 其他函数
      • 精度数学
    • SQL 语句语法
      • 数据定义语句 (DDL)
      • 数据操作语句 (DML)
      • 事务语句
      • 数据库管理语句
      • Prepared SQL 语句语法
      • 实用工具语句
      • TiDB SQL 语法图
    • JSON 支持
    • Connectors 和 API
    • TiDB 事务隔离级别
    • 错误码与故障诊断
    • 与 MySQL 兼容性对比
    • TiDB 内存控制
    • 慢查询日志
    • 高级功能
      • 历史数据回溯
      • 垃圾回收 (GC)
  • TiDB 运维文档
    • 软硬件环境需求
    • 部署集群
      • Ansible 部署方案(强烈推荐)
      • 离线 Ansible 部署方案
      • Docker 部署方案
      • Docker Compose 部署方案
      • 跨机房部署方案
    • 配置集群
      • 参数解释
      • TiDB 配置项解释
      • 使用 Ansible 变更组件配置
      • 开启 TLS 验证
      • 生成自签名证书
    • 监控集群
      • 整体监控框架概述
      • 重要监控指标详解
      • 组件状态 API & 监控
    • 扩容缩容
      • 集群扩容缩容方案
      • 使用 Ansible 扩容缩容
    • 升级
      • 升级组件版本
      • TiDB 2.0 升级操作指南
    • 性能调优
    • 备份与迁移
      • 备份与恢复
      • 数据迁移
        • 数据迁移概述
        • 全量导入
        • 增量导入
    • 故障诊断
  • TiDB 周边工具
    • Syncer
    • Loader
    • TiDB-Binlog
    • PD Control
    • PD Recover
    • TiKV Control
    • TiDB Controller
  • TiSpark 文档
    • TiSpark 快速入门指南
    • TiSpark 用户指南
  • 常见问题与解答(FAQ)
  • 最佳实践
  • 版本发布历史
    • 2.1 RC3
    • 2.1 RC2
    • 2.0.7
    • 2.1 RC1
    • 2.0.6
    • 2.0.5
    • 2.1 Beta
    • 2.0.4
    • 2.0.3
    • 2.0.2
    • 2.0.1
    • 2.0
    • 2.0 RC5
    • 2.0 RC4
    • 2.0 RC3
    • 2.0 RC1
    • 1.1 Beta
    • 1.1 Alpha
    • 1.0
    • Pre-GA
    • RC4
    • RC3
    • RC2
    • RC1
  • TiDB 路线图
  • 用户案例
    • 北京银行
    • 海航
    • 今日头条
    • 转转
    • Mobike
    • 饿了么(一)
    • 饿了么(二)
    • 爱奇艺
    • 易果生鲜
    • 同程旅游
    • 去哪儿
    • G7
    • 一面数据
    • 凤凰网
    • 猿辅导
    • Mobikok
    • 二维火
    • 客如云
    • Ping++
    • 乐视云
    • 零氪科技
    • 威锐达测控
    • 盖娅互娱
    • 游族网络
    • 西山居
    • FUNYOURS JAPAN
    • 特来电
    • 万达网络
    • 360金融
    • 中国电信翼支付
    • 某电信运营商
  • 更多资源
    • 常用工具
    • PingCAP 团队技术博客
    • 知乎专栏
    • Weekly
    • 英文文档

TiDB 事务隔离级别

事务隔离级别是数据库事务处理的基础,ACID 中 I,即 Isolation,指的就是事务的隔离性。

sql 92标准定义了4种隔离级别,读未提交、读已提交、可重复读、串行化,见下表。

Isolation Level Dirty Read Nonrepeatable Read Phantom Read Serialization Anomaly
Read uncommitted Possible Possible Possible Possible
Read committed Not possible Possible Possible Possible
Repeatable read Not possible Not possible Not possible in TiDB Possible
Serializable Not possible Not possible Not possible Not possible

TiDB 实现了其中的可重复读。

TiDB 使用 Percolator 事务模型,当事务启动时会获取全局读时间戳,事务提交时也会获取全局提交时间戳,并以此确定事务的执行顺序,如果想了解 TiDB 事务模型的实现可以详细阅读以下两篇文章:TiKV 的 MVCC (Multi-Version Concurrency Control) 机制,Percolator 和 TiDB 事务算法。

可重复读

当事务隔离级别为可重复读时,只能读到该事务启动时已经提交的其他事务修改的数据,未提交的数据或在事务启动后其他事务提交的数据是不可见的。对于本事务而言,事务语句可以看到之前的语句做出的修改。

对于运行于不同节点的事务而言,不同事务启动和提交的顺序取决于从 PD 获取时间戳的顺序。

处于可重复读隔离级别的事务不能并发的更新同一行,当时事务提交时发现该行在该事务启动后,已经被另一个已提交的事务更新过,那么该事务会回滚并启动自动重试。示例如下:

create table t1(id int);
insert into t1 values(0);

start transaction;              |               start transaction;
select * from t1;               |               select * from t1;
update t1 set id=id+1;          |               update t1 set id=id+1;
commit;                         |
                                |               commit; --回滚并自动重试

与 ANSI 可重复读隔离级别的区别

尽管名称是可重复读隔离级别,但是 TiDB 中可重复读隔离级别和 ANSI 可重复隔离级别是不同的,按照 A Critique of ANSI SQL Isolation Levels 论文中的标准,TiDB 实现的是论文中的 snapshot 隔离级别,该隔离级别不会出现幻读,但是会出现写偏斜,而 ANSI 可重复读隔离级别不会出现写偏斜,会出现幻读。

与MySQL可重复读隔离级别的区别

MySQL 可重复读隔离级别在更新时并不检验当前版本是否可见,也就是说,即使该行在事务启动后被更新过,同样可以继续更新。这种情况在 TiDB 会导致事务回滚并后台重试,重试最终可能会失败,导致事务最终失败,而 MySQL 是可以更新成功的。 MySQL 的可重复读隔离级别并非 snapshot 隔离级别,MySQL 可重复读隔离级别的一致性要弱于 snapshot 隔离级别,也弱于 TiDB 的可重复读隔离级别。

事务重试

对于 insert/delete/update 操作,如果事务执行失败,并且系统判断该错误为可重试,会在系统内部自动重试事务。

通过配置参数 retry-limit 可控制自动重试的次数:

[performance]
...
# The maximum number of retries when commit a transaction.
retry-limit = 10

乐观事务注意事项

因为 TiDB 使用乐观锁机制,通过显式的 BEGIN 语句创建的事务,在遇到冲突后自动重试可能会导致最终结果不符合预期。

比如下面这两个例子:

Session1 Session2
begin; begin;
select balance from t where id = 1; update t set balance = balance -100 where id = 1;
update t set balance = balance -100 where id = 2;
// 使用 select 的结果决定后续的逻辑 commit;
if balance > 100 {
update t set balance = balance + 100 where id = 2;
}
commit; // 自动重试
Session1 Session2
begin; begin;
update t set balance = balance - 100 where id = 1; delete t where id = 1;
commit;
// 使用 affected_rows 的结果决定后续的逻辑
if affected_rows > 100 {
update t set balance = balance + 100 where id = 2;
}
commit; // 自动重试

因为 TiDB 自动重试机制会把事务第一次执行的所有语句重新执行一遍,当一个事务里的后续 语句是否执行取决于前面语句执行结果的时候,自动重试无法保证最终结果符合预期。 这种情况下,需要在应用层重试整个事务。

通过配置全局变量 tidb_disable_txn_auto_retry 可以关掉显式事务的重试。

set @@global.tidb_disable_txn_auto_retry = 1;

这个变量不会影响 auto_commit = 1 的单语句的隐式事务,仍然会自动重试。

关掉显示事务重试后,如果出现事务冲突,commit 语句会返回错误,错误信息会包含 try again later 这个字符串,应用层可以用来判断遇到的错误是否是可以重试的。

如果事务执行过程中包含了应用层的逻辑,建议在应用层添加显式事务的重试,并关闭自动重试。

语句回滚

在事务内部执行一个语句,遇到错误时,该语句不会生效。

begin;
insert into test values (1);
insert into tset values (2);  // tset 拼写错了,这条语句出错。
insert into test values (3);
commit;

上面的例子里面,第二个语句失败,其它插入 1 和 3 仍然能正常提交。

begin;
insert into test values (1);
insert into tset values (2);  // tset 拼写错了,这条语句出错。
insert into test values (3);
rollback;

这个例子中,第二个语句失败,最后由于调用了 rollback,事务不会将任何数据写入数据库。

"TiDB 事务隔离级别" 更新于 Sep 10 2018: sql: remove documentation about read committed (c4a4394)
修改本文

本页导航

产品

  • TiDB
  • TiSpark
  • TiDB 路线图

文档

  • 快速入门
  • 最佳实践
  • 常见问题解答
  • TiDB 周边工具
  • 版本发布说明

资源

  • 博客
  • GitHub
  • 知乎专栏

公司

  • 关于我们
  • 招贤纳士
  • 新闻报道

联系我们

  • Twitter
  • LinkedIn
  • Reddit
  • Google Group
  • Stack Overflow
  • 微信公众号

    微信扫一扫
    微信ID:pingcap2015

© 2018 北京平凯星辰科技发展有限公司

English