1. 前言

本文主要分为三个部分:

  • 第一个部分为 MySQL 事务的特性;
  • 第二个部分为 MySQL 事务的隔离级别;
  • 第三个部分为 MySQL 常见锁机制;
  • 第四个部分为具体的实践案例。

2. 💡问题思考

  1. MySQL 事务是什么?

    • MySQL 事务是指一组 SQL 语句,它们被当成一个单独的工作单元, 要么全部执行成功,要么全部不执行。
    1
    2
    3
    4
    5
    6
    7
    假设你有一个银行账户,你要向另一个账户转账 1000 元。
    这个操作涉及到两个 SQL 语句:一个是从你的账户扣除 1000 元,另一个是给对方的账户增加 1000 元。
    如果你不使用事务,那么可能会出现以下情况:
    1. 第一个 SQL 语句执行成功,但是第二个 SQL 语句执行失败,导致你的钱少了 1000 元,但是对方没有收到。
    2. 第一个 SQL 语句执行失败,但是第二个 SQL 语句执行成功,导致你的钱没有变化,但是对方多了 1000 元。
    3. 第一个 SQL 语句执行成功,但是在第二个 SQL 语句执行之前,有其他人查询了你或对方的账户余额,看到了不正确的数据。
    这些情况都会造成数据的不一致和不完整。如果你使用事务,那么你可以保证两个 SQL 语句要么都执行成功,要么都不执行。
  2. MySQL 事务解决了什么问题?

    • 针对上诉问题,事务最少是需要满足一致性和隔离性。

    • 脏读:一个事务读取了另一个事务未提交的数据,不符合一致性

    • 不可重复读:一个事务读取了另一个事务已经提交的 update 操作的数据,导致前后两次查询结果不一致,不符合隔离性
    • 幻读:一个事务读取了另一个事务已经提交的 insert 操作的数据,导致前后两次查询结果不一致,不符合隔离性
  3. MySQL 事务隔离级别是什么?

    • MySQL 的事务隔离级别是指在多个事务并发运行时,互相是如何隔离的,从而来避免一些事务并发运行时产生的问题
    • SQL 标准中规定了四种事务隔离级别:读未提交(Read Uncommitted)读已提交(Read Committed)可重复读(Repeatable Read)串行化(Serializable
    1
    2
    3
    4
    5
    6
    假设有两个人 A 和 B,他们都要从银行取钱。
    A 先开始取钱,他将银行卡中的余额从 1000 元改为 800 元,但是还没有完成取钱。此时,B 开始取钱,他需要查询银行卡中的余额。
    如果 B 的隔离级别是读未提交,则 B 可以读取到 A 修改后的余额 800 元;
    如果 B 的隔离级别是读已提交,则 B 只能读取到 A 修改前的余额 1000 元;
    如果 B 的隔离级别是可重复读,则 B 只能读取到 A 修改前的余额 1000 元;
    如果 B 的隔离级别是串行化,则 B 必须等待 A 完成取钱后才能开始查询。

3. 事务特性

事务是由一组 SQL 语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的 ACID 属性。

  • 原子性(Atomicity) :事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
  • 一致性(Consistent) :在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性。
  • 隔离性(Isolation) :数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
  • 持久性(Durable) :事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

4. 事务隔离级别

从问题思考中,我们知道事务的隔离级别主要分为以下四类:

  • 读未提交(Read Uncommitted)
  • 读已提交(Read Committed)
  • 可重复读(Repeatable Read)
  • 串行化(Serializable

而事务隔离级别主要解决了以下主要的三个问题:

  • 脏读
  • 不可重复读
  • 幻读

Mysql 默认的事务隔离级别是可重复读,用Spring开发程序时,如果不设置隔离级别默认用 Mysql 设置的隔离级别,如果 Spring 设置了就用已经设置的隔离级别

  • 脏读不可重复读幻读,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。
隔离级别 脏读(Dirty Read) 不可重复读(NonRepeatable Read) 幻读(Phantom Read)
读未提交(Read uncommitted) 可能 可能 可能
读已提交(Read committed) 不可能 可能 可能
可重复读(Repeatableread) 不可能 不可能 可能
可串行化(Serializable) 不可能 不可能 不可能
  • 查看当前数据库的事务隔离级别:
1
show variables like 'tx_isolation';
  • 设置事务隔离级别:
1
set tx_isolation='REPEATABLE-READ';

5.

锁的本质是解决了 计算机协调多个进程或线程并发访问某一资源的机制。