Skip to content

Commit

Permalink
transactions: improve clarity of transactions (#4577)
Browse files Browse the repository at this point in the history
  • Loading branch information
ireneontheway authored Sep 29, 2020
1 parent 4a77a1e commit bdb0238
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 59 deletions.
18 changes: 9 additions & 9 deletions optimistic-transaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ aliases: ['/docs-cn/dev/optimistic-transaction/','/docs-cn/dev/reference/transac

# TiDB 乐观事务模型

本文介绍 TiDB 乐观事务的原理,以及相关特性
乐观事务模型下,将修改冲突视为事务提交的一部分。因此并发事务不常修改同一行时,可以跳过获取行锁的过程进而提升性能。但是并发事务频繁修改同一行(冲突)时,乐观事务的性能可能低于[悲观事务](/pessimistic-transaction.md)

TiDB 的乐观事务模型只有在两阶段事务提交时才会检测是否存在写写冲突
启用乐观事务前,请确保应用程序可正确处理 `COMMIT` 语句可能返回的错误。如果不确定应用程序将会如何处理,建议改为使用悲观事务

> **注意:**
>
> 自 v3.0.8 开始,新创建的 TiDB 集群默认使用[悲观事务模型](/pessimistic-transaction.md)。但如果从 3.0.7 及之前版本创建的集群升级到 >= 3.0.8 的版本,不会改变默认事务模型,即**只有新创建的集群才会默认使用悲观事务模型**
> 自 v3.0.8 开始,TiDB 集群默认使用[悲观事务模型](/pessimistic-transaction.md)。但如果从 3.0.7 及之前版本创建的集群升级到 3.0.8 及之后的版本,不会改变默认事务模型,即**只有新创建的集群才会默认使用悲观事务模型**
## 乐观事务原理

Expand Down Expand Up @@ -69,11 +69,11 @@ TiDB 的乐观事务模型只有在两阶段事务提交时才会检测是否存

### 重试机制

当事务提交时,如果发现写写冲突,TiDB 内部重新执行包含写操作的 SQL 语句。你可以通过设置 `tidb_disable_txn_auto_retry = off` 开启自动重试,并通过 `tidb_retry_limit` 设置重试次数:
当事务提交时,如果发现写写冲突,TiDB 内部重新执行包含写操作的 SQL 语句。你可以通过设置 `tidb_disable_txn_auto_retry = OFF` 开启自动重试,并通过 `tidb_retry_limit` 设置重试次数:

```toml
# 设置是否禁用自动重试,默认为 “on”,即不重试。
tidb_disable_txn_auto_retry = off
tidb_disable_txn_auto_retry = OFF
# 控制重试次数,默认为 “10”。只有自动重试启用时该参数才会生效。
# 当 “tidb_retry_limit= 0” 时,也会禁用自动重试。
tidb_retry_limit = 10
Expand All @@ -86,27 +86,27 @@ tidb_retry_limit = 10
{{< copyable "sql" >}}

```sql
set @@tidb_disable_txn_auto_retry = off;
SET tidb_disable_txn_auto_retry = OFF;
```

{{< copyable "sql" >}}

```sql
set @@tidb_retry_limit = 10;
SET tidb_retry_limit = 10;
```

- Global 级别设置:

{{< copyable "sql" >}}

```sql
set @@global.tidb_disable_txn_auto_retry = off;
SET GLOBAL tidb_disable_txn_auto_retry = OFF;
```

{{< copyable "sql" >}}

```sql
set @@global.tidb_retry_limit = 10;
SET GLOBAL tidb_retry_limit = 10;
```

> **注意:**
Expand Down
31 changes: 26 additions & 5 deletions pessimistic-transaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ aliases: ['/docs-cn/dev/pessimistic-transaction/','/docs-cn/dev/reference/transa
{{< copyable "sql" >}}

```sql
set @@global.tidb_txn_mode = 'pessimistic';
SET GLOBAL tidb_txn_mode = 'pessimistic';
```

除此之外,还可以执行以下 SQL 语句显式地开启悲观事务:
Expand All @@ -33,7 +33,7 @@ BEGIN PESSIMISTIC;
{{< copyable "sql" >}}

```
BEGIN /*!90000 PESSIMISTIC */;
BEGIN /*T! PESSIMISTIC */;
```

`BEGIN PESSIMISTIC;``BEGIN OPTIMISTIC;` 等语句的优先级高于 `tidb_txn_mode` 系统变量。使用这两个语句开启的事务,会忽略系统变量,从而支持悲观、乐观事务混合使用。
Expand All @@ -60,17 +60,38 @@ BEGIN /*!90000 PESSIMISTIC */;

## 和 MySQL InnoDB 的差异

1. TiDB 使用 range 作为 WHERE 条件,执行 DML `SELECT FOR UPDATE` 语句时不会阻塞范围内并发的 `INSERT` 语句的执行。
1. 有些 `WHERE` 子句中使用了 range,TiDB 在执行这类 DML 语句和 `SELECT FOR UPDATE` 语句时,不会阻塞 range 内并发的 DML 语句的执行。

InnoDB 通过实现 gap lock,支持阻塞 range 内并发的 `INSERT` 语句的执行,其主要目的是为了支持 statement based binlog,因此有些业务会通过将隔离级别降低至 Read Committed 来避免 gap lock 导致的并发性能问题。TiDB 不支持 gap lock,也就不需要付出相应的并发性能的代价。
举例:

```sql
CREATE TABLE t1 (
id INT NOT NULL PRIMARY KEY,
pad1 VARCHAR(100)
);
INSERT INTO t1 (id) VALUES (1),(5),(10);
```

```sql
BEGIN /*T! PESSIMISTIC */;
SELECT * FROM t1 WHERE id BETWEEN 1 AND 10 FOR UPDATE;
```

```sql
BEGIN /*T! PESSIMISTIC */;
INSERT INTO t1 (id) VALUES (6); -- 仅 MySQL 中出现阻塞。
UPDATE t1 SET pad1='new value' WHERE id = 5; -- MySQL 和 TiDB 处于等待阻塞状态。
```

产生这一行为是因为 TiDB 当前不支持 _gap locking_(间隙锁)。

2. TiDB 不支持 `SELECT LOCK IN SHARE MODE`

使用这个语句执行的时候,效果和没有加锁是一样的,不会阻塞其他事务的读写。

3. DDL 可能会导致悲观事务提交失败。

MySQL 在执行 DDL 时会被正在执行的事务阻塞住,而在 TiDB 中 DDL 操作会成功,造成悲观事务提交失败:`ERROR 1105 (HY000): Information schema is changed. [try again later]`。TiDB 事务执行过程中并发执行 `TRUNCATE TABLE` 语句,可能会导致事务报错 `table dosen't exist`
MySQL 在执行 DDL 语句时,会被正在执行的事务阻塞住,而在 TiDB 中 DDL 操作会成功,造成悲观事务提交失败:`ERROR 1105 (HY000): Information schema is changed. [try again later]`。TiDB 事务执行过程中并发执行 `TRUNCATE TABLE` 语句,可能会导致事务报错 `table doesn't exist`

4. `START TRANSACTION WITH CONSISTENT SNAPSHOT` 之后,MySQL 仍然可以读取到之后在其他事务创建的表,而 TiDB 不能。

Expand Down
2 changes: 1 addition & 1 deletion system-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ SET GLOBAL tidb_distsql_scan_concurrency = 10;

- 作用域:SESSION | GLOBAL
- 默认值:ON
- 这个变量用来设置是否自动 Commit 事务
- 用于设置在非显式事务时是否自动提交事务。更多信息,请参见[事务概述](/transaction-overview.md#自动提交)

### `allow_auto_random_explicit_insert` <span class="version-mark">从 v4.0.3 版本开始引入</span>

Expand Down
Loading

0 comments on commit bdb0238

Please sign in to comment.