mysql 第8.1章 事务-介绍 mysql 第8.1章 事务-介绍

2019-08-25

一、什么是 mysql 的事务

Mysql 事务主要用来处理数据量大、数据复杂度高的数据操作,最经典的使用场景是银行的转账:需要先从银行账户 A 中取出钱,然后再存入银行账户 B 中,如果中间出现问题,而没有事务的保证,那么就会出现 B 收不到钱,而A支出钱又回不到自己的账户的严重问题,那么有了事务机制,这个问题就解决了。

二、事务的特点

  • 在 Mysql 中,只有数据库引擎 InnoDB 支持事务机制;

  • 事务可用来维护数据结构及数据的完整性,确保批量的操作要么全部执行,要么全部不执行;

  • 事务是用来管理数据表的 insert、update 及 delete 的

三、事务的ACID

①、A(Atomicity),即事务的原子性

原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。

比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。

②、C(Consistency),即事务的一致性

一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。

例如现有完整性约束a+b=10,如果一个事务改变了a,那么必须得改变b,使得事务结束后依然满足a+b=10,否则事务失败。

③、I(Isolation),即事务的独立性

所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。

比如现在有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的。

④、D(Durability),即事务的持久性

持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。

四、事务的隔离

①、并发时遇到的问题

在事务并发操作时,经常出现一些问题,这些问题可用几个术语名词描述:

A、脏读

一个事务读取了另一个事务并发写的未提交的数据,比如:事务 A 读取了事务 B 写入的数据,但是 B 事务并未提交,后来其撤销了修改,此时事务 A 就读取了不该读取的数据。

B、幻读

一个事务重复读取数据,在获得的数据行中发现某些数据是其它事务最近操作的数据,比如:事务 A 反复执行查询语句查询数据表,而这时另一事务 B 正在操作该表,恰好的是事务 B 操作的数据正符合事务 A 查询的条件,而事务 A 再读取时,发现结果集发生了变化,这在并发事务时经常出现。

C、不可重复读

一个事务重复读取之前读取过的数据,后发现读取的数据被另一个事务所修改,比如:事务 A 反复读取指定的数据,而此时事务 B 正好操作该数据,当事务 A 再次查询时,发现之前读取的数据已经变化。

注:上面事务并发出现的问题,可以通过设置事务的隔离来处理,但不能完全依赖事务隔离,而是应该在应用程序中恰当的使用锁来控制并发访问,两者的结合是解决的问题关键。

②、事务的隔离级别

事务隔离级别分为4种:

READ UNCOMMITED // 允许幻读,脏读及不可重复读;
READ COMMITED   // 允许幻读和不可重复读,不允许脏读;
REPEATABLE READ // 允许幻读,不允许脏读和不可重复读;
SERIALIZABLE READ // 不允许幻读,脏读及不可重复读;

注:Mysql默认的是 REPEATABLEREAD 级别。另外,随着事务的隔离级别越高,并发执行的性能就越低,所以适当选择级别并结合业务需求来选定级别设置。

③、设置事务隔离级别

A、查询Mysql系统隔离默认级别:

SELECT @@global.tx_isolation;

B、查询Mysql会话隔离默认级别:

SELECT @@tx_isolation;

C、修改系统及会话隔离级别

这里我们将事务的级别修改为 READ COMMITED:

SET global transaction isolation level read committed;
SET session transaction isolation level read committed;

④、四种事务隔离级别

SQL 标准定义了四种事务隔离级别,每种级别在并发场景下会表现出不同的行为。这四种隔离级别从低到高分别是:

https://cyfb.lulublog.cn/images/3/2026/04/mg0qThnNLnepl0llEH4wPzSasNFTaQ.png

A、读未提交(Read Uncommitted)最低级别,可能发生脏读。

特点:允许一个事务读取另一个未提交事务所修改的数据。

问题:可能导致-脏读(Dirty Read)。即,一个事务可以读到另一个事务尚未提交的数据,如果该事务回滚,读到的数据就是无效的。

应用场景:很少使用,通常用于不需要严格数据一致性的场景,因为它提供的隔离性最低。

B、读已提交(Read Committed)避免脏读,但可能发生不可重复读。

特点:只允许事务读取已提交的数据。即,一个事务只能读取到其他事务已经提交的数据。

问题:可能导致-不可重复读(Non-repeatable Read)。即,在同一个事务中,多次读取同一行数据,结果可能不同,因为其他事务可能在期间修改并提交了该数据。

应用场景:是许多数据库的默认隔离级别(如 Oracle)。适用于不需要数据完全一致但希望避免脏读的场景。

C、可重复读(Repeatable Read)避免脏读和不可重复读,但可能发生幻读。

特点:确保在同一事务中,多次读取同一行数据的结果是一致的。事务开始后,其他事务的修改在当前事务中不可见。

问题:可能导致-幻读(Phantom Read)。即,一个事务在读取某个条件下的行时,如果另一个事务插入了符合条件的新行,前一个事务再次查询时会看到 "幻影" 行。

应用场景:常用于需要避免不可重复读的场景,MySQL 默认使用此隔离级别。

D、可串行化(Serializable)最高级别,避免所有并发问题,但性能开销最大。

特点:是最高级别的隔离,确保事务完全串行化执行,仿佛所有事务是一个接一个顺序执行的,而非并发执行的。

问题:解决了幻读问题,但代价是并发性能显著降低,可能导致大量的锁竞争,降低系统的并发能力。

应用场景:用于数据一致性要求非常高的场景,但通常代价较高。

五、事务的锁定

为什么要给事务加锁?是因为高并发访问操作数据时,会存在正在读取某数据时,其它进程会删除会修改该数据,为了保证数据的完整性,需要对进程共享数据加锁控制。

务锁的分类:

①、按照对数据的操作类型划分:

  • 读锁(共享锁)-针对同一块数据,多个读操作可同时进行互补影响。

  • 写锁(排它锁)-针对同一块数据,当前写操作未完成,它会阻止其它操作进行。

②、按照锁定数据的范围划分:

  • 表锁 -MyIsam引擎默认使用的锁。当写入数据时,把整张表锁住,其它的读,写操作都不进行,一律等待当前写操作完成,特点:开销小,并发量小。

  • 行锁 -InnoDB及Falcon引用默认使用的锁。当写入数据时,把当前操作的数据行锁定,其它读,写操作一律等待,特点:开销适中,并发量大。

注:Mysql是一种开放式数据库架构,是允许自定义存储引擎的,而Oracle及Sql server是不允许自定义修改的。

六、事务的操作

开启一个事务

START TRANSACTION | BEGIN;

提交关闭事务

COMMIT;

保存事务快照

SAVE POINT save_point_name;  // save_point_name保存事务点名字

回滚事务(点)

ROLLBACK save_point_name

七、Lock wait timeout exceeded

  • 你使用的 InnoDB 表类型的时候, 默认参数:innodb_lock_wait_timeout 设置锁等待的时间是 50s,锁等待超过了这个时间就会报错

  • innodb_lock_wait_timeout 锁定等待时间改大 my.ini文件:

  • #innodb_lock_wait_timeout = 50 修改为 innodb_lock_wait_timeout = 500

八、事务 DDL

  • DDL:Data Definition Language,数据定义语言

    • 创建数据库:CREATE DATABASE

    • 创建数据库表格:CREATE TABLE

    • 修改数据库表格:ALTER TABLE

    • 删除数据库表格:DROP TABLE

    • 创建查询命令:CREATE VIEW

    • 修改查询命令:ALTER VIEW

    • 删除查询命令:DROP VIEW

    • 删除数据表内容:TRUNCATE TABLE

  • 避免在事务中执行 DDL:尽量预先建好表,而不是在创建用户时动态 CREATE TABLE。如果必须动态建表,请确保建表操作在事务逻辑之外,或者使用非事务方式处理。

  • 检查数据库引擎:确保所有涉及到的表都支持事务(如 MySQL 的 InnoDB 引擎),不支持事务的引擎(如 MylSAM)会导致事务指令无效

  • 手动状态检查:在调用提交或回滚前,先检查事务状态(例如使用 PHP PDO 的 $pdo->inTransaction() 方法)以确保安全性

九、事务是怎么保证最终一致性

MySQL事务通过以下几个机制来保证最终一致性:

  • ACID 特性:事务遵循原子性、一致性、隔离性和持久性,确保操作要么全部成功,要么全部失败。

  • 隔离级别:MySQL提供多种隔离级别(如读未提交、读已提交、可重复读、串行化),以控制事务之间的可见性,避免脏读、不可重复读和幻读。

  • 日志机制:使用日志(如重做日志和撤销日志)来记录事务操作,以便在发生故障时进行恢复。

  • 锁机制:通过行级锁和表级锁来管理并发,确保在同一时间只有一个事务可以修改某些数据。

这些机制共同作用,确保即使在系统故障或并发操作的情况下,数据最终也能保持一致。

阅读 4000

mysql文章
带到手机上看