TiDB 事务概览

    本文主要介绍涉及事务的常用语句、显式/隐式事务、事务的隔离级别和惰性检查,以及事务大小的限制。

    常用的变量包括 、tidb_disable_txn_auto_retry、 以及 tidb_txn_mode

    要显式地开启一个新事务,既可以使用 语句,也可以使用 START TRANSACTION 语句,两者效果相同。

    语法:

    1. START TRANSACTION;
    1. START TRANSACTION WITH CONSISTENT SNAPSHOT;

    如果执行以上语句时,当前 Session 正处于一个事务的中间过程,那么系统会先自动提交当前事务,再开启一个新的事务。

    语句用于提交 TiDB 在当前事务中进行的所有修改。

    语法:

    1. COMMIT;

    ROLLBACK 语句用于回滚并撤销当前事务的所有修改。

    如果客户端连接中止或关闭,也会自动回滚该事务。

    自动提交

    为满足 MySQL 兼容性的要求,在默认情况下,TiDB 将在执行语句后立即进行 autocommit(自动提交)。

    举例:

    1. mysql> CREATE TABLE t1 (
    2. -> id INT NOT NULL PRIMARY KEY auto_increment,
    3. -> pad1 VARCHAR(100)
    4. -> );
    5. Query OK, 0 rows affected (0.09 sec)
    6. mysql> SELECT @@autocommit;
    7. +--------------+
    8. | @@autocommit |
    9. +--------------+
    10. | 1 |
    11. +--------------+
    12. 1 row in set (0.00 sec)
    13. mysql> INSERT INTO t1 VALUES (1, 'test');
    14. Query OK, 1 row affected (0.02 sec)
    15. mysql> ROLLBACK;
    16. Query OK, 0 rows affected (0.01 sec)
    17. mysql> SELECT * FROM t1;
    18. +----+------+
    19. | id | pad1 |
    20. +----+------+
    21. | 1 | test |
    22. +----+------+
    23. 1 row in set (0.00 sec)

    以上示例中,ROLLBACK 语句没产生任何效果。由于 INSERT 语句是在自动提交的情况下执行的,等同于以下单语句事务:

    1. START TRANSACTION;
    2. INSERT INTO t1 VALUES (1, 'test');
    3. COMMIT;

    如果已显式地启动事务,则不适用自动提交。以下示例, 语句成功撤回了 INSERT 语句:

    1. -> id INT NOT NULL PRIMARY KEY auto_increment,
    2. -> pad1 VARCHAR(100)
    3. -> );
    4. Query OK, 0 rows affected (0.10 sec)
    5. mysql> SELECT @@autocommit;
    6. +--------------+
    7. | @@autocommit |
    8. +--------------+
    9. | 1 |
    10. +--------------+
    11. 1 row in set (0.00 sec)
    12. mysql> START TRANSACTION;
    13. Query OK, 0 rows affected (0.00 sec)
    14. mysql> INSERT INTO t2 VALUES (1, 'test');
    15. Query OK, 1 row affected (0.02 sec)
    16. mysql> ROLLBACK;
    17. Query OK, 0 rows affected (0.00 sec)
    18. mysql> SELECT * FROM t2;
    19. Empty set (0.00 sec)

    是一个系统变量,可以基于 Session 或 Global 进行修改

    举例:

    1. SET GLOBAL autocommit = 0;

    TiDB 可以显式地使用事务(通过 [BEGIN|START TRANSACTION]/COMMIT 语句定义事务的开始和结束) 或者隐式地使用事务 (SET autocommit = 1)。

    在自动提交状态下,使用 [BEGIN|START TRANSACTION] 语句会显式地开启一个事务,同时也会禁用自动提交,使隐式事务变成显式事务。直到执行 COMMITROLLBACK 语句时才会恢复到此前默认的自动提交状态。

    对于 DDL 语句,会自动提交并且不能回滚。如果运行 DDL 的时候,正在一个事务的中间过程中,会先自动提交当前事务,再执行 DDL。

    惰性检查

    举例:

    1. CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY);
    2. INSERT INTO t1 VALUES (1);
    3. BEGIN OPTIMISTIC;
    4. INSERT INTO t1 VALUES (1); -- MySQL 返回错误;TiDB 返回成功。
    5. INSERT INTO t1 VALUES (2);
    6. COMMIT; -- MySQL 提交成功;TiDB 返回错误,事务回滚。
    7. SELECT * FROM t1; -- MySQL 返回 1 2TiDB 返回 1
    1. mysql> CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY);
    2. Query OK, 0 rows affected (0.10 sec)
    3. mysql> INSERT INTO t1 VALUES (1);
    4. Query OK, 1 row affected (0.02 sec)
    5. mysql> BEGIN OPTIMISTIC;
    6. Query OK, 0 rows affected (0.00 sec)
    7. mysql> INSERT INTO t1 VALUES (2);
    8. Query OK, 1 row affected (0.00 sec)
    9. mysql> COMMIT; -- MySQL 提交成功;TiDB 返回错误,事务回滚。
    10. ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
    11. mysql> SELECT * FROM t1; -- MySQL 返回 1 2TiDB 返回 1
    12. +----+
    13. | id |
    14. +----+
    15. | 1 |
    16. +----+
    17. 1 row in set (0.01 sec)

    惰性检查优化通过批处理约束检查并减少网络通信来提升性能。可以通过设置 禁用该行为。

    TiDB 支持语句执行失败后的原子性回滚。如果语句报错,则所做的修改将不会生效。该事务将保持打开状态,并且在发出 COMMITROLLBACK 语句之前可以进行其他修改。

    1. mysql> CREATE TABLE test (id INT NOT NULL PRIMARY KEY);
    2. Query OK, 0 rows affected (0.09 sec)
    3. mysql> BEGIN;
    4. Query OK, 0 rows affected (0.00 sec)
    5. mysql> INSERT INTO test VALUES (1);
    6. Query OK, 1 row affected (0.02 sec)
    7. mysql> INSERT INTO tset VALUES (2); -- tset 拼写错误,使该语句执行出错。
    8. ERROR 1146 (42S02): Table 'test.tset' doesn't exist
    9. mysql> INSERT INTO test VALUES (1),(2); -- 违反 PRIMARY KEY 约束,语句不生效。
    10. ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
    11. mysql> INSERT INTO test VALUES (3);
    12. Query OK, 1 row affected (0.00 sec)
    13. mysql> COMMIT;
    14. Query OK, 0 rows affected (0.01 sec)
    15. mysql> SELECT * FROM test;
    16. +----+
    17. | id |
    18. +----+
    19. | 1 |
    20. | 3 |
    21. +----+
    22. 2 rows in set (0.00 sec)

    以上例子中,INSERT 语句执行失败之后,事务保持打开状态。最后的 INSERT 语句执行成功,并且提交了修改。

    事务限制

    由于底层存储引擎的限制,TiDB 要求单行不超过 6 MB。可以将一行的所有列根据类型转换为字节数并加和来估算单行大小。

    TiDB 同时支持乐观事务与悲观事务,其中乐观事务是悲观事务的基础。由于乐观事务是先将修改缓存在私有内存中,因此,TiDB 对于单个事务的容量做了限制。

    TiDB 中,单个事务的总大小默认不超过 100 MB,这个默认值可以通过配置文件中的配置项 txn-total-size-limit 进行修改,最大支持 10 GB。实际的单个事务大小限制还取决于服务器剩余可用内存的大小,执行事务时 TiDB 进程的内存消耗大约是事务大小的 6 倍以上。

    在 4.0 以前的版本,TiDB 限制了单个事务的键值对的总数量不超过 30 万条,从 4.0 版本起 TiDB 取消了这项限制。