Skip to content

Commit

Permalink
disable transaction auto retry (#784)
Browse files Browse the repository at this point in the history
  • Loading branch information
coocood authored and shenli committed Jun 28, 2018
1 parent 593ade3 commit 5c183c2
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 0 deletions.
10 changes: 10 additions & 0 deletions sql/tidb-specific.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 优化器会尽量使用指定的算法,在某些场景下会比默认算法更优。
Expand Down
46 changes: 46 additions & 0 deletions sql/transaction-isolation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` 这个字符串,应用层可以用来判断遇到的错误是否是可以重试的。

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

## 语句回滚

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

0 comments on commit 5c183c2

Please sign in to comment.