
# 事务
事务（Transaction）是数据库管理系统执行过程中的最小逻辑单位，由一个有限的数据库操作序列构成（通常由事务开始与事务结束之间执行的全部数据库操作组成）。这些操作要么全部成功执行，要么全部不执行，是一个不可分割的执行单位。
当事务提交时，数据库管理系统必须确保事务中的所有操作都成功完成。如果事务中的任何一部分操作未成功，系统会将数据库回滚到事务开始之前的状态。以下是事务的四个特性（ACID）：
- 原子性（Atomicity）整个事务中的所有操作，要么全部完成，要么全部不完成，不可停滞在某个中间环节。
- 一致性（Consistency）事务必须始终保持系统处于一致的状态。
- 隔离性（Isolation）隔离性确保并发执行的事务彼此隔离，不会互相干扰。
- 持久性（Durability）一旦事务提交，对数据库的改变应该永久保存在数据库中。
 
#### 事务隔离级别
- 脏读、幻读、不可重复读介绍：
  - 脏读：当前事务能读取到另一个事务尚未提交的数据。
  
  - 幻读：在同一个事务中，多次执行相同的查询时，由于其他事务的插入和删除操作，导致结果集中的行数发生变化。
  
  - 不可重复读：在同一个事务中，多次读取同一数据时，由于其他事务的修改操作，导致读取的结果不一致。
   
- GaussDB隔离级别的特点：
  - Read Committed（读已提交）：默认的隔离级别。当前事务只能读取到其他事务已提交的数据，从而避免了脏读。但是其他事务可以在两次读取期间修改或者插入数据导致出现幻读和不可重复读的情况。
  
  - Repeatable Read（可重复读）：当前事务在执行期间可以看到一致的数据，避免了脏读和不可重复读。
  
  - Serializable（可串行化）：GaussDB目前功能上不支持此隔离级别，设置该隔离级别时，等价于REPEATABLE READ。
   
 
#### 事务控制语句
- START TRANSACTION：开启事务，如果声明了隔离级别、读写模式，那么新事务就使用这些特性。此语句在使用过程中可选。
- BEGIN：开启事务，如果声明了隔离级别、读写模式，那么新事务就使用这些特性。此语句在使用过程中可选。
  - 会话的系统变量autocommit的值为off时，表示关闭事务自动提交功能，就不需要BEGIN或者START TRANSACTION命令来标识多个SQL组成的一个事务。
  
  - 会话的系统变量autocommit的值为on时，表示开启事务自动提交功能，该模式下，每条SQL都是一个独立的事务。如果还要多个SQL组成一个事务，就需要BEGIN或者START TRANSACTION命令开启一个事务。
   

- SAVEPOINT：用于在当前事务里新建一个保存点。保存点是事务中的一个特殊记号，它允许将那些在它建立后执行的命令全部回滚，把事务的状态恢复到保存点所在的时刻。
- COMMIT\|END：提交并结束当前事务，让所有的修改持久化并生效，清除所有保存点释放事务锁。
- ROLLBACK：回滚整个事务已做的修改，清除所有保存点释放事务锁。
- ROLLBACK TO SAVEPOINT：回滚到一个保存点，隐含地删除所有在该保存点之后建立的保存点。
 
#### 语法格式
- START TRANSACTION
  ```
  START TRANSACTION
    [ 
      { 
         ISOLATION LEVEL { READ COMMITTED | READ UNCOMMITTED | SERIALIZABLE | REPEATABLE READ }
         | { READ WRITE | READ ONLY }
       } [, ...] 
    ];
  ```
  
- BEGIN
  ```
  BEGIN [ WORK | TRANSACTION ]
    [ 
      { 
         ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE | REPEATABLE READ | READ UNCOMMITTED }
         | { READ WRITE | READ ONLY }
        } [, ...] 
    ];
  ```
  
- SAVEPOINT
  ```
  SAVEPOINT savepoint_name;
  ```
  
- ROLLBACK TO SAVEPOINT
  ```
  ROLLBACK [ WORK | TRANSACTION ] TO [ SAVEPOINT ] savepoint_name;
  ```
  
 
#### 示例
```
--建表。
gaussdb=# CREATE TABLE test1(c1 INT);
--以隔离级别为READ COMMITTED，读/写方式启动事务。
gaussdb=# START TRANSACTION ISOLATION LEVEL READ COMMITTED READ WRITE;
START TRANSACTION
--插入数据。
gaussdb=# INSERT INTO test1 (c1) VALUES (1);
INSERT 0 1
--建立一个保存点。
gaussdb=# SAVEPOINT my_savepoint;
SAVEPOINT
--插入数据。
gaussdb=# INSERT INTO test1 (c1) VALUES (2);
INSERT 0 1
--回滚到保存点。
gaussdb=# ROLLBACK TO SAVEPOINT my_savepoint;
ROLLBACK
--查看数据，可以看到数据已经回滚到保存点之前的状态。
gaussdb=# SELECT * FROM test1;
 c1 
----
  1
(1 row)
--由于隔离级别是READ COMMITTED且事务还没有结束，所以新开一个会话查看该表没有任何数据。
gaussdb=# SELECT * FROM test1;
 c1 
----
(0 rows)
--插入数据。
gaussdb=# INSERT INTO test1 (c1) VALUES (3);
INSERT 0 1
--结束事务。
gaussdb=# COMMIT;
COMMIT
--查看数据，事务已经结束，在另一个会话中可以查询到数据。
gaussdb=# SELECT * FROM test1;
 c1 
----
  3
  1
(2 rows)
--删除表。
gaussdb=# DROP TABLE test1;
DROP TABLE
```
