# 事务基础

URL: https://caijiao.org/postgresql/performance/transactions/basic
Source: docs/postgresql/performance/transactions/basic.md
Description: 本章节介绍 PostgreSQL 中的事务基础，包括事务的概念、ACID 特性、常用事务命令等内容。

事务是数据库管理系统（DBMS）中用于保证数据一致性、可靠性和完整性的一个重要机制。PostgreSQL 中的事务提供了一种方式来确保一组操作要么完全成功，要么完全失败。事务通过支持 ACID 特性来保证数据的完整性。

## 事务的概念

事务是一组要么完全执行，要么完全不执行的操作。事务的目的是确保数据库始终处于一致的状态，防止部分操作成功导致数据不一致的情况。

### ACID 特性

PostgreSQL 的事务遵循 ACID 特性，这四个字母代表：

- **原子性（Atomicity）**：事务中的操作要么全部成功，要么全部失败，不会发生部分成功的情况。
- **一致性（Consistency）**：事务执行前后，数据库的状态是一致的，符合所有的约束和规则。
- **隔离性（Isolation）**：多个事务并发执行时，每个事务都是独立的，一个事务的执行不应影响其他事务的执行。
- **持久性（Durability）**：一旦事务提交，对数据库的修改将被永久保存，即使系统崩溃也不应丢失。

## 开始事务

在 PostgreSQL 中，事务是通过 `BEGIN` 和 `COMMIT` 或 `ROLLBACK` 命令来管理的。

### 1. 开始事务

使用 `BEGIN` 或 `START TRANSACTION` 命令来启动一个事务。

#### 语法：

```sql
-- 启动一个事务
BEGIN;

-- 或者
START TRANSACTION;
````

#### 示例：

```sql
BEGIN;
```

### 2. 提交事务

使用 `COMMIT` 命令提交事务，使得事务中的所有更改永久生效。

#### 语法：

```sql
-- 提交事务
COMMIT;
```

#### 示例：

```sql
COMMIT;
```

### 3. 回滚事务

如果事务中出现了错误，可以使用 `ROLLBACK` 命令回滚事务，撤销事务中的所有更改。

#### 语法：

```sql
-- 回滚事务
ROLLBACK;
```

#### 示例：

```sql
ROLLBACK;
```

## 事务隔离级别

事务隔离级别定义了多个事务并发执行时如何相互影响。PostgreSQL 支持以下隔离级别：

### 1. 读未提交（Read Uncommitted）

在此隔离级别下，一个事务可以读取其他事务未提交的数据。由于此级别会读取“脏数据”，因此通常不推荐使用。

### 2. 读已提交（Read Committed）

这是 PostgreSQL 的默认隔离级别。在此级别下，一个事务只能读取其他已提交事务的数据。其他事务的修改在当前事务提交后才会可见。

### 3. 可重复读（Repeatable Read）

在此隔离级别下，事务始终读取自己开始时的数据快照。其他事务的修改在当前事务完成之前对当前事务不可见。

### 4. 串行化（Serializable）

这是最高的隔离级别，事务完全隔离。所有事务按顺序执行，确保数据的一致性，但会牺牲性能。

#### 设置事务隔离级别的语法：

```sql
-- 设置事务隔离级别为 READ COMMITTED（默认）
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 设置事务隔离级别为 SERIALIZABLE
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
```

#### 示例：

```sql
-- 设置事务隔离级别为 SERIALIZABLE
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
-- 执行事务操作
COMMIT;
```

## 锁机制

PostgreSQL 使用行级锁和表级锁来保证事务的隔离性。

### 1. 行级锁

行级锁是对特定行数据的锁定，允许多个事务并发地修改不同的行。当一个事务对一行数据加锁时，其他事务无法修改该行数据，直到事务提交或回滚。

#### 锁定行的语法：

```sql
-- 锁定选定的行
SELECT * FROM table_name WHERE condition FOR UPDATE;
```

#### 示例：

```sql
-- 锁定 employees 表中 id 为 1 的行
SELECT * FROM employees WHERE id = 1 FOR UPDATE;
```

### 2. 表级锁

表级锁是对整个表进行锁定。通常表级锁的粒度较大，适用于修改表结构等操作。

#### 锁定表的语法：

```sql
-- 锁定整个表
LOCK TABLE table_name IN LOCK_MODE;
```

#### 示例：

```sql
-- 对 employees 表加排他锁
LOCK TABLE employees IN EXCLUSIVE MODE;
```

## 事务常见命令

### 1. SAVEPOINT

`SAVEPOINT` 命令用于在事务中创建一个保存点，这样可以在出现错误时回滚到某个保存点，而不是回滚整个事务。

#### 语法：

```sql
-- 创建保存点
SAVEPOINT savepoint_name;

-- 回滚到保存点
ROLLBACK TO SAVEPOINT savepoint_name;
```

#### 示例：

```sql
-- 创建一个保存点
SAVEPOINT sp1;

-- 执行一些操作

-- 如果出现错误，可以回滚到保存点
ROLLBACK TO SAVEPOINT sp1;
```

### 2. COMMIT 和 ROLLBACK 结合使用

在复杂的事务中，可以根据业务逻辑判断是否提交或回滚事务。如果没有发生错误，可以提交事务；如果出现错误，可以回滚事务。

#### 示例：

```sql
BEGIN;

-- 执行一些操作
INSERT INTO employees (name, age) VALUES ('Alice', 30);

-- 如果没有错误，提交事务
COMMIT;

-- 如果发生错误，回滚事务
ROLLBACK;
```

## 小结

事务是确保数据库一致性和完整性的重要机制，PostgreSQL 提供了灵活的事务管理功能，支持不同的事务隔离级别和锁机制。在使用事务时，合理配置事务隔离级别和使用合适的锁机制，可以有效提高数据库的性能和并发处理能力。
