Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sql: disable transaction auto retry #784

Merged
merged 3 commits into from
Jun 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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