从零开始学习MySQL 事务处理

2024-05-11 12:12

本文主要是介绍从零开始学习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. 异常处理:如果在结算过程中有任何问题,比如某个商品库存不足,系统会捕获错误并回滚事务,保证数据库状态不变,避免了部分商品被错误减少库存而订单未创建的情况。

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

 

 

 

这篇关于从零开始学习MySQL 事务处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/979496

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

SQL中的外键约束

外键约束用于表示两张表中的指标连接关系。外键约束的作用主要有以下三点: 1.确保子表中的某个字段(外键)只能引用父表中的有效记录2.主表中的列被删除时,子表中的关联列也会被删除3.主表中的列更新时,子表中的关联元素也会被更新 子表中的元素指向主表 以下是一个外键约束的实例展示

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

如何去写一手好SQL

MySQL性能 最大数据量 抛开数据量和并发数,谈性能都是耍流氓。MySQL没有限制单表最大记录数,它取决于操作系统对文件大小的限制。 《阿里巴巴Java开发手册》提出单表行数超过500万行或者单表容量超过2GB,才推荐分库分表。性能由综合因素决定,抛开业务复杂度,影响程度依次是硬件配置、MySQL配置、数据表设计、索引优化。500万这个值仅供参考,并非铁律。 博主曾经操作过超过4亿行数据

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]