From de8589d40110731639a6a4aa33664cf72a44d331 Mon Sep 17 00:00:00 2001 From: Ewan Chou Date: Thu, 28 Jun 2018 15:16:34 +0800 Subject: [PATCH 1/3] disable transaction auto retry --- sql/transaction-isolation.md | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/sql/transaction-isolation.md b/sql/transaction-isolation.md index b9342b7e8bc5..aeed4b94dc7a 100644 --- a/sql/transaction-isolation.md +++ b/sql/transaction-isolation.md @@ -77,6 +77,52 @@ MySQL 的可重复读隔离级别并非 snapshot 隔离级别,MySQL 可重复 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` 这个字符串,应用层可以用来判断遇到的错误是否是可以重试的。 + +如果事务执行过程中包含了应用层的逻辑,建议在应用层添加显式事务的重试,并关闭自动重试。 + ## 语句回滚 在事务内部执行一个语句,遇到错误时,该语句不会生效。 From 1e2473510a56f12c50657f2a66b4516fcb6215ac Mon Sep 17 00:00:00 2001 From: Ewan Chou Date: Thu, 28 Jun 2018 15:24:24 +0800 Subject: [PATCH 2/3] add tidb-specific --- sql/tidb-specific.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sql/tidb-specific.md b/sql/tidb-specific.md index ae21e0619ea6..3d47cd97d4e6 100644 --- a/sql/tidb-specific.md +++ b/sql/tidb-specific.md @@ -285,6 +285,16 @@ TiDB 在 MySQL 的基础上,定义了一些专用的系统变量和语法用 这个变量用来设置最多可重试次数, 即在一个事务执行中遇到可重试的错误(例如事务冲突、TiKV 繁忙等)时,这个事务可以被重新执行,这个变量值表明最多可重试的次数。 +### tidb_disable_txn_auto_retry + +作用域:SESSION | GLOBAL + +默认值:0 + +这个变量用来设置是否禁用显式事务自动重试,设置为 1 时,不会自动重试,如果遇到冲突需要在应用层重试。 +是否需要禁用自动重试,请参考[自动重试的风险](./transaction-isolation.md#事务重试的风险) + + ## Optimizer Hint TiDB 在 MySQL 的 Optimizer Hint 语法上,增加了一些 TiDB 专有的 Hint 语法, 使用这些 Hint 的时候,TiDB 优化器会尽量使用指定的算法,在某些场景下会比默认算法更优。 From c1eadfb67d072ea5cde84b77204f734c239445a3 Mon Sep 17 00:00:00 2001 From: Ewan Chou Date: Thu, 28 Jun 2018 15:30:25 +0800 Subject: [PATCH 3/3] refine the words --- sql/tidb-specific.md | 2 +- sql/transaction-isolation.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/tidb-specific.md b/sql/tidb-specific.md index 3d47cd97d4e6..da5ce5cb8d54 100644 --- a/sql/tidb-specific.md +++ b/sql/tidb-specific.md @@ -292,7 +292,7 @@ TiDB 在 MySQL 的基础上,定义了一些专用的系统变量和语法用 默认值:0 这个变量用来设置是否禁用显式事务自动重试,设置为 1 时,不会自动重试,如果遇到冲突需要在应用层重试。 -是否需要禁用自动重试,请参考[自动重试的风险](./transaction-isolation.md#事务重试的风险) +是否需要禁用自动重试,请参考[自动重试的风险](./transaction-isolation.md#乐观事务注意事项) ## Optimizer Hint diff --git a/sql/transaction-isolation.md b/sql/transaction-isolation.md index aeed4b94dc7a..9816d1025a72 100644 --- a/sql/transaction-isolation.md +++ b/sql/transaction-isolation.md @@ -77,9 +77,9 @@ MySQL 的可重复读隔离级别并非 snapshot 隔离级别,MySQL 可重复 retry-limit = 10 ``` -## 事务重试的风险 +## 乐观事务注意事项 -因为 TiDB 使用乐观锁机制,通过显式的 BEGIN 语句创建的事务,在遇到冲突后自动重试可能会导致最终结果不正确。 +因为 TiDB 使用乐观锁机制,通过显式的 BEGIN 语句创建的事务,在遇到冲突后自动重试可能会导致最终结果不符合预期。 比如下面这两个例子: