从零开始学习MySQL 事务处理

 事务处理与ACID特性

事务是数据库操作的基本单元,它确保一组操作要么全部成功,要么全部失败,以此来维护数据库的一致性。这四个字母缩写ACID代表了事务的四大特性:

原子性(Atomicity)**:事务被视为不可分割的最小工作单元,事务中的所有操作要么全部执行,要么全部不执行。
一致性(Consistency)**:事务执行前后,数据库的状态保持合法,即符合所有的预定义规则。
隔离性(Isolation)**:并发执行的事务之间互不影响,仿佛是在一个个独立的环境中执行。
持久性(Durability)**:一旦事务被提交,其效果就会永久保存在数据库中,即使系统发生故障也不会丢失。

下面通过几个案例来展示如何在MySQL中使用事务处理及不同隔离级别的影响。

# 基础事务处理案例

假设我们要从一个账户转账到另一个账户,需要两个操作:从账户A减去金额,向账户B增加相同的金额。这两个操作必须在一个事务中执行,以确保数据的一致性。

```sql

START TRANSACTION;

-- 从账户A扣款

UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;

-- 向账户B加款

UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;

-- 提交事务

COMMIT;


```

如果在执行完第一个`UPDATE`后,程序崩溃或遇到错误,由于没有执行`COMMIT`,事务中的所有操作都会被回滚,从而保证了数据的一致性。

# 隔离级别的演示

MySQL支持四种事务隔离级别:读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ,InnoDB的默认级别)和串行化(SERIALIZABLE)。不同的隔离级别会影响事务并发执行时的行为。

## 读未提交(READ UNCOMMITTED)

这种隔离级别下,一个事务可以看到其他事务未提交的更改。

```sql

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

-- 在一个事务中更改但未提交

START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;

-- 在另一个事务中读取未提交的更改

START TRANSACTION;
SELECT balance FROM accounts WHERE account_id = 1;


```

## 读已提交(READ COMMITTED)

在此隔离级别下,事务只能看到已提交的更改。

```sql

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 事务1提交更改

START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
COMMIT;

-- 事务2能看到已提交的更改

START TRANSACTION;
SELECT balance FROM accounts WHERE account_id = 1;


```

## 可重复读(REPEATABLE READ)

这是InnoDB的默认隔离级别,保证了在同一个事务中多次读取同一数据的结果是一致的,即使其他事务已经修改并提交了该数据。

```sql

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 事务1读取余额

START TRANSACTION;
SELECT balance FROM accounts WHERE account_id = 1;

-- 事务2更改余额并提交

START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
COMMIT;

-- 事务1再次读取余额,结果不变

SELECT balance FROM accounts WHERE account_id = 1;


```

## 串行化(SERIALIZABLE)

最高隔离级别,通过锁定读取的行来避免并发冲突,相当于顺序执行事务。

```sql

SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- 事务1读取余额

START TRANSACTION;
SELECT balance FROM accounts WHERE account_id = 1;

-- 事务2尝试更新,但会被阻塞直到事务1结束

START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;


```

通过这些案例,我们可以直观地看到不同隔离级别下事务行为的差异,以及它们如何影响数据库的一致性和并发性能。在实际应用中,应根据业务需求选择最合适的隔离级别。

 

Demo1:银行转账

想象一下,你正在使用手机银行应用给朋友转账。这个过程涉及两个关键操作:从你的账户扣除一定金额,同时在你朋友的账户上增加相同金额。为了确保整个过程的准确无误,银行系统就需要使用事务来处理这笔转账操作。

#### 场景设定:

- 你的账户(Account A)余额为500元。
- 你朋友的账户(Account B)余额为300元。
- 你想转账200元给朋友。

#### 无事务处理的情况(想象中的灾难):

如果银行系统没有使用事务,转账可能这样进行:
1. 银行系统从Account A中减去了200元,此时你的账户余额变为300元。
2. 就在这个时候,突然停电了或者系统出现了故障,导致给Account B增加200元的操作没有完成。

结果:你的钱减少了,而你朋友并没有收到钱,这就是一个典型的不一致状态,显然不符合我们的预期。

#### 使用事务处理的情况(安全可靠):

现在,让我们看看事务是如何确保操作的完整性的:

1. **开始事务**:银行系统启动一个事务,准备执行转账操作。
   
   ```sql

   START TRANSACTION;


   ```

2. **扣款操作**:从你的账户减去200元。
   
   ```sql
 

  UPDATE accounts SET balance = balance - 200 WHERE account_id = 'A';


   ```

3. **加款操作**:增加你朋友账户的金额。
   
   ```sql
 

  UPDATE accounts SET balance = balance + 200 WHERE account_id = 'B';


   ```

4. **提交事务**:如果上述两步都成功完成,银行系统提交事务,所有更改永久保存。
   
   ```sql
 

 COMMIT;


   ```

5. **异常处理**:但如果在执行上述操作的过程中发生了任何错误(比如系统故障),事务管理器会检测到这一情况,并执行:
   
   ```sql

   ROLLBACK;


   ```
   这样,之前对Account A的扣款操作会被撤销,账户余额回到500元,就像转账从未发生过一样,保证了数据的完整性。

通过这个例子,我们可以清晰地理解事务如何确保数据的一致性,即使在复杂的操作序列中也能保证“要么全做,要么全不做”的原则,这对于涉及金钱交易、库存管理等敏感操作的系统至关重要。

 Demo2:图书馆借阅系统中的事务处理

设想一个图书馆管理系统,其中涉及图书的借出和归还操作。这个过程同样需要事务来确保数据的准确性和一致性。

# 场景描述:

- 图书馆有《编程珠玑》这本书,当前库存为1本。
- 用户小王想要借阅这本书。

# 借书过程的事务处理:

1. 开始事务:系统启动事务,准备记录借书操作。

   ```sql
   

START TRANSACTION;


   ```

2. 检查库存:确认《编程珠玑》是否有可供借阅的副本。
   
   ```sql
 

  SELECT stock FROM books WHERE title = '编程珠玑' AND available = true;


   ```

3. 更新库存:如果书籍可用,则减少书籍的可用库存,并记录小王借阅的信息。
   
   ```sql

   UPDATE books SET available = false WHERE title = '编程珠玑';
   INSERT INTO borrow_records (book_title, borrower, borrow_date) VALUES ('编程珠玑', '小王', NOW());


   ```

4. 提交事务:如果上述操作都成功,事务提交,借书操作完成。
   
   ```sql
 

 COMMIT;


   ```

5. 异常处理:如果在借书过程中出现任何问题,比如网络中断、数据库错误等,事务会自动回滚,确保数据的一致性。
   
   ```sql
   

ROLLBACK;


   ```

# 归还过程的事务处理:

当小王归还《编程珠玑》时,也需要通过事务确保操作的原子性和一致性:

1. 开始事务:同借书操作一样,先启动事务。

2. 更新记录:标记书籍为可借状态,并记录归还时间。
   
   ```sql
   

UPDATE books SET available = true WHERE title = '编程珠玑';
UPDATE borrow_records SET return_date = NOW() WHERE book_title = '编程珠玑' AND borrower = '小王' AND return_date IS NULL;


   ```

3. 提交事务:操作成功后提交事务,完成归还流程。

4. 异常处理:遇到错误时回滚事务,确保书籍状态和借阅记录的准确性。

通过这些例子,我们可以看到,无论是银行转账还是图书馆借阅系统,事务处理都是确保数据一致性和完整性的关键机制。在涉及多个数据库操作的情境下,事务能够保证数据的一致性和业务逻辑的正确执行,即使在复杂的系统交互中也能保持数据的准确无误。

 

 更多实例:在线购物车结算过程中的事务处理

设想一个电商平台,用户将商品加入购物车后,决定一次性结算多个商品。这个过程中,涉及到从库存中减少已购买商品的数量,并更新订单信息,同样需要事务来确保操作的原子性和一致性。

# 场景描述:

- 用户张三的购物车中有三件商品:商品A(库存10)、商品B(库存5)、商品C(库存2)。
- 张三决定购买商品A 2件,商品B 3件,商品C 1件。

# 结算过程的事务处理:

1. 开始事务:系统启动事务,准备处理订单创建及库存更新。

   ```sql
   

START TRANSACTION;


   ```

2. 检查库存:验证购物车中每种商品的购买数量是否小于等于现有库存。
   
   ```sql
   

SELECT stock FROM products WHERE product_id IN ('A', 'B', 'C') AND stock >= (SELECT quantity FROM cart WHERE user_id = '张三' AND product_id = products.product_id);


   ```

3. 更新库存:如果所有商品的库存都满足购买需求,减少相应商品的库存数量。
   
   ```sql
   

UPDATE products SET stock = stock - (SELECT quantity FROM cart WHERE user_id = '张三' AND 
    product_id = 'A') WHERE product_id = 'A';
UPDATE products SET stock = stock - (SELECT quantity FROM cart WHERE user_id = '张三' AND 
    product_id = 'B') WHERE product_id = 'B';
UPDATE products SET stock = stock - (SELECT quantity FROM cart WHERE user_id = '张三' AND 
    product_id = 'C') WHERE product_id = 'C';


   ```

4. 创建订单:记录订单信息,包括用户信息、商品详情、购买数量等。
   
   ```sql

INSERT INTO orders (user_id, product_id, quantity, order_date) VALUES ('张三', 'A', (SELECT quantity FROM cart WHERE user_id = '张三' AND product_id = 'A'), NOW()), ('张三', 'B', (SELECT quantity FROM cart WHERE user_id = '张三' AND product_id = 'B'), NOW()), ('张三', 'C', (SELECT quantity FROM cart WHERE user_id = '张三' AND product_id = 'C'), NOW());


   ```

5. 清空购物车:完成购买后,清空用户购物车中已结算的商品。
   
   ```sql
   

DELETE FROM cart WHERE user_id = '张三' AND product_id IN ('A', 'B', 'C');


   ```

6. 提交事务:所有操作成功后,提交事务,完成结算流程。
   
   ```sql
 

 COMMIT;


   ```

7. 异常处理:如果在结算过程中有任何问题,比如某个商品库存不足,系统会捕获错误并回滚事务,保证数据库状态不变,避免了部分商品被错误减少库存而订单未创建的情况。

通过这个例子,我们可以看到事务在电子商务平台中的重要作用,它确保了库存的精确管理、订单的准确生成以及购物车状态的一致性,即便在面对复杂且并发的用户操作时,也能维持系统的稳定和数据的准确。

 

 

 

相关推荐

  1. 开始学习MySQL 事务处理

    2024-05-11 11:06:06       26 阅读
  2. 开始学习MySQL

    2024-05-11 11:06:06       31 阅读
  3. 开始精通Onvif之事件处理

    2024-05-11 11:06:06       31 阅读
  4. 开始学习Linux》——开篇

    2024-05-11 11:06:06       28 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-11 11:06:06       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-11 11:06:06       100 阅读
  3. 在Django里面运行非项目文件

    2024-05-11 11:06:06       82 阅读
  4. Python语言-面向对象

    2024-05-11 11:06:06       91 阅读

热门阅读

  1. ubuntu 查看 postgresql 用户

    2024-05-11 11:06:06       33 阅读
  2. 商品购物车数据以店铺id为key,组合对应的数据

    2024-05-11 11:06:06       35 阅读
  3. 1、搭建TS开发环境(利用rollup)

    2024-05-11 11:06:06       37 阅读
  4. python dict赋值时有逗号自动变成元组

    2024-05-11 11:06:06       33 阅读
  5. 每天一个数据分析题(三百一十九)-图表

    2024-05-11 11:06:06       28 阅读
  6. 【前端每日一题】 day3

    2024-05-11 11:06:06       41 阅读
  7. 深度学习中超参数设置

    2024-05-11 11:06:06       34 阅读
  8. linux phpstudy 重启命令

    2024-05-11 11:06:06       34 阅读
  9. SSH简介:安全远程访问的基石

    2024-05-11 11:06:06       33 阅读