
# 主动终止空闲事务
#### 操作场景
当一个事务长时间空闲且不提交，执行回滚操作时，会对数据库的资源和性能造成损耗。如果有大量的空闲事务长期不执行也不提交，在业务高峰期的时候发生回滚，性能损耗会较为严重。TaurusDB支持主动终止空闲事务，可针对不同类型的事务（只读事务、读写事务）用不同的参数进行控制，当空闲事务超时后会被自动的回滚并断开连接。
- 读写事务：事务中执行了INSERT、UPDATE、DELETE等写操作。
- 只读事务：事务中仅执行了SELECT查询，或使用**START TRANSACTION READ ONLY**显式开启。
 
#### 什么是空闲
一条连接的生命周期是在"等待客户端发送命令"和"执行客户端命令"之间交替进行的，空闲即服务端正在等待客户端发送下一条命令。 SQL 正在执行期间，无论执行耗时多久，都不属于"空闲"，不会被任何空闲超时机制断开。
TaurusDB具备两层空闲超时机制，连接空闲超时和事务空闲超时。
表1TaurusDB空闲超时机制 
| 分类     | 控制参数                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | 适用场景             | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | 超时后的行为                                                                                                                                                                                                                                                                                                                                                                                                                       |
|:---|:---|:---|:---|:---|
| 连接空闲超时 | - wait_timeout：交互式连接空闲超时时间。  - interactive_timeout： 非交互式连接空闲超时时间。                                                                                                     | 连接上未开启事务，或不在事务中。 | 通用机制，任何连接空闲超过此时间都会被断开。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | 断开连接。                                                                                                                                                                                                                                                                                                                                                                                                                        |
| 事务空闲超时 | - idle_readonly_transaction_timeout：只读事务空闲超时时间。  - idle_write_transaction_timeout：读写事务空闲超时时间。  - idle_transaction_timeout：一般空闲事务超时时间。   | 连接上存在未提交的活动事务。   | 事务中的空闲连接相较于普通连接具有更高的资源占用风险： 1. 锁资源占用：可能持有未释放的行锁或表锁，导致并发阻塞；  2. 事务槽位占用：消耗事务日志缓冲区（Transaction Slot）资源，影响系统吞吐量；  3. 垃圾回收延迟：阻碍未提交事务的垃圾回收（GC）进程，增加存储压力。   因此在连接空闲超时基础上，TaurusDB提供事务空闲超时机制，对处于事务中的连接提供更短的超时控制。 | 超时触发后，服务端会执行以下操作： 1. 回滚事务：所有未提交的修改被撤销。  2. 断开连接：客户端收到错误：\`ERROR 2013 (HY000): Lost connection to MySQL server during query\`。    |
   
表2参数对比 
| 对比项  | idle_transaction_timeout系列                             | wait_timeout /interactive_timeout |
|:---|:---|:---|
| 适用场景 | 连接上存在未提交的活动事务。                                         | 所有连接，不区分是否在事务中。                   |
| 默认值  | 0（不生效，需显式设置）。                                          | 28800秒（8 小时）。                     |
| 超时值  | 可按只读/读写分别设置更短的超时值。                                     | 不区分事务类型，统一超时值。                    |
| 超时行为 | 断开连接，未提交事务自动回滚。                                        | 断开连接，未提交事务自动回滚。                   |
| 优先级  | 处于事务中时，idle_\*transaction_timeout 系列值优先于 wait_timeout。 | 作为基础超时值，事务空闲超时值不超过此值。             |
   
#### 前提条件
内核版本为2.0.39.230300及以后的版本支持该功能。内核版本的查询方法请参见[如何查看云数据库 TaurusDB实例的版本号](https://support.huaweicloud.com/taurusdb_faq/taurusdb_faq_0141.html)。
#### 约束限制
- 三个参数默认均为0，即默认不启用空闲事务超时，需要显式设置才会生效。
- 超时触发后，未提交事务自动回滚，客户端无法收到友好的错误提示，仅收到 ERROR 2013。
- 参数为 SESSION 级别，可针对不同会话设置不同的超时策略，也可在 GLOBAL 级别统一设置。
- 事务超时后数据回滚不可恢复，请在业务侧做好重试机制。
- 建议对读写事务设置更短的超时时间，读写事务持有锁资源，长时间空闲对其他事务影响更大。
- 空闲超时只计算等待命令的时间，SQL 正在执行期间不会触发空闲超时，无论执行多久。
- 事务空闲超时值不会超过wait_timeout，如果设置的idle_transaction_timeout大于wait_timeout，实际生效值仍为wait_timeout。
 
#### 参数介绍
```
show variables like '%idle%';
+------------------------------------+------+
| Variable_name                     | Value |
+-----------------------------------+-------+
| idle_readonly_transaction_timeout | 0     |
| idle_transaction_timeout         | 0     |
| idle_write_transaction_timeout   | 0     |
+-----------------------------------+-------+
```
表3参数说明 
| **参数名**                           | **级别**         | **参数描述**                                                                                              |
|:---|:---|:---|
| idle_readonly_transaction_timeout | global、session | 控制只读事务连接的超时时间，单位为秒。 参数设置为0时不生效，即表示只读事务连接的超时时间没有限制。      |
| idle_transaction_timeout          | global、session | 控制一般空闲事务连接的超时时间，单位为秒。 参数设置为0时不生效，即表示一般空闲事务的连接超时时间没有限制。 |
| idle_write_transaction_timeout    | global、session | 控制读写事务连接的超时时间，单位为秒。 参数设置为0时不生效，即表示读写事务连接的超时时间没有限制。   |
   
上述三个参数不是独立校验的，而是按优先级逐级检查。
1. idle_readonly_transaction_timeout和idle_write_transaction_timeout的优先级高于idle_transaction_timeout。
2. 若idle_readonly_transaction_timeout或idle_write_transaction_timeout为0，继续校验idle_transaction_timeout。若idle_transaction_timeout=0，则该类型事务不启用空闲事务超时。
3. 上述三个参数均为 0，则不启用空闲事务超时，空闲事务不会因此被终止。
表4事务超时参数生效机制 
| idle_readonly_transaction_timeout | idle_write_transaction_timeout | idle_transaction_timeout | 只读事务超时                              | 读写事务超时                           |
|:---|:---|:---|:---|:---|
| \> 0                              | \> 0                           | 任意                       | idle_readonly_transaction_timeout生效 | idle_write_transaction_timeout生效 |
| \> 0                              | = 0                            | \> 0                     | idle_readonly_transaction_timeout生效 | idle_transaction_timeout生效       |
| \> 0                              | = 0                            | = 0                      | idle_readonly_transaction_timeout生效 | 不生效                              |
| = 0                               | \> 0                           | \> 0                     | idle_transaction_timeout生效          | idle_write_transaction_timeout生效 |
| = 0                               | \> 0                           | = 0                      | 不生效                                 | idle_write_transaction_timeout生效 |
| = 0                               | = 0                            | \> 0                     | idle_transaction_timeout生效          | idle_transaction_timeout生效       |
| = 0                               | = 0                            | = 0                      | 不生效                                 | 不生效                              |
   
#### 示例
#### 示例1：只读事务和读写事务超时时间为0，空闲事务不为0
- **设置参数**
  idle_transaction_timeout=10，idle_readonly_transaction_timeout=0，idle_write_transaction_timeout=0
  
- **作用效果**
  只读事务和读写事务均采用10秒超时。
  表5作用效果 
  | 事务类型 | 生效参数                     | 超时时间 |
  |:---|:---|:---|
  | 只读事务 | idle_transaction_timeout | 10秒  |
  | 读写事务 | idle_transaction_timeout | 10秒  |
     
  
- **效果验证**
  - 只读事务
    ```
    begin;
    Query OK, 0 rows affected (0.00 sec)
    ```
    在"idle_transaction_timeout"设置的10s范围以外执行一次查询操作，结果如下：
    ```
    select * from t1;
    ERROR 2013 (HY000): Lost connection to MySQL server during query
    ```
    
  
  
  
  - 读写事务 使用begin开启事务之前，执行查询语句，查询结果如下：
    ```
    select * from t1;
    +---------+
    | col_int |
    +---------+
    |       1 |
    +---------+
    1 row in set (0.00 sec)
    ```
    ```
    begin;
    Query OK, 0 rows affected (0.00 sec)
    ```
    ```
    insert into t1 values(2);
    Query OK, 1 row affected (0.00 sec)
    ```
    在"idle_transaction_timeout"设置的10s范围以外执行一次查询操作，结果如下：
    ```
    select * from t1;
    ERROR 2013 (HY000): Lost connection to MySQL server during query
    ```
    新建一个连接，执行查询语句，结果如下，表示此时事务已经回滚。
    ```
    select * from t1;
    +---------+
    | col_int |
    +---------+
    |       1 |
    +---------+
    1 row in set (0.00 sec)
    ```
    
   
 
#### 示例2：读写事务超时时间不为0
- **设置参数**
  idle_transaction_timeout=10，idle_readonly_transaction_timeout=0，idle_write_transaction_timeout=15
  
- **作用效果**
  读写事务采用15秒超时，只读事务因 idle_readonly_transaction_timeout 为0，故采用 idle_transaction_timeout 参数的值。
  表6作用效果 
  | 事务类型 | 生效参数                           | 超时时间 |
  |:---|:---|:---|
  | 只读事务 | idle_transaction_timeout       | 10秒  |
  | 读写事务 | idle_write_transaction_timeout | 15秒  |
     
  
- **效果验证**
  使用begin开启事务之前，执行查询语句，查询结果如下：
  ```
  select * from t1;
  +---------+
  | col_int |
  +---------+
  |       2 |
  +---------+
  1 row in set (0.00 sec)
  ```
  ```
  begin;
  Query OK, 0 rows affected (0.00 sec)
  ```
  ```
  insert into t1 values(3);
  Query OK, 1 row affected (0.00 sec)
  ```
  在"idle_write_transaction_timeout"设置的15s范围以外执行一次查询操作，结果如下：
  ```
  select * from t1;
  ERROR 2013 (HY000): Lost connection to MySQL server during query
  ```
  新建一个连接，执行查询语句，结果如下，表示此时事务已经回滚。
  ```
  select * from t1;
  +---------+
  | col_int |
  +---------+
  |       2 |
  +---------+
  1 row in set (0.01 sec)
  ```
  
 
#### 示例3：只读事务超时时间不为0
- **设置参数**
  idle_transaction_timeout=0，idle_readonly_transaction_timeout=15，idle_write_transaction_timeout=0
  
- **作用效果**
  只读事务采用15秒超时，读写事务因idle_readonly_transaction_timeout和idle_transaction_timeout均为0，故不启用空闲事务超时。
  表7作用效果 
  | 事务类型 | 生效参数                              | 超时时间 |
  |:---|:---|:---|
  | 只读事务 | idle_readonly_transaction_timeout | 15秒  |
  | 读写事务 | 不生效                               | -    |
     
  
- **效果验证**
  ```
  begin;
  Query OK, 0 rows affected (0.00 sec)
  ```
  在"idle_readonly_transaction_timeout"设置的15s范围以外执行一次查询操作，结果如下：
  ```
  select * from t1;
  ERROR 2013 (HY000): Lost connection to MySQL server during query
  ```
  
 
#### 示例4：只读事务、读写事务、空闲事务超时均不为0
- **设置参数**
  idle_transaction_timeout=30，idle_readonly_transaction_timeout=15，idle_write_transaction_timeout=10
  
- **作用效果**
  只读事务采用15秒超时，读写事务采用10秒超时。
  idle_transaction_timeout 在此配置中不会被任何事务使用，因为idle_readonly_transaction_timeout和idle_write_transaction_timeout均不为0，其优先级高于idle_transaction_timeout。
  表8作用效果 
  | 事务类型 | 生效参数                              | 超时时间 |
  |:---|:---|:---|
  | 只读事务 | idle_readonly_transaction_timeout | 15秒  |
  | 读写事务 | idle_write_transaction_timeout    | 10秒  |
     
  
 
