17MySQL事务

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了17MySQL事务相关的知识,希望对你有一定的参考价值。

事务特性

mysql事务是一组SQL语句,它们被视为单个工作单元,要么全部执行成功,要么全部失败回滚。MySQL使用事务来保证在多个并发用户之间的数据一致性。

MySQL事务遵循ACID原则,即:

原子性(Atomicity):一个事务是一个不可分割的工作单位,事务中的所有操作要么全部完成,要么全部不完成。

一致性(Consistency):当事务完成时,所有数据都必须处于一致的状态,即数据库从一个一致性状态转移到另一个一致性状态。

隔离性(Isolation):每个事务都应该在另一个事务提交之前独立运行,不应该互相干扰。

持久性(Durability):一旦事务提交,它对数据库中的数据更改应该是永久的,即使发生系统故障也应该是如此。

管理事务

显示启动事务

START TRANSACTION;
BEGIN
BEGIN WORK

注意:只有事务型存储引擎中的DML语句方能支持此类操作 ,包括SELECT、INSERT、UPDATE、DELETE等。

17、MySQL事务_死锁

17、MySQL事务_commit_02

17、MySQL事务_死锁_03

17、MySQL事务_事务隔离级别_04

结束事务

如果事务执行成功,使用以下语句提交:

COMMIT;

如果事务执行失败,使用以下语句回滚:

ROLLBACK;

17、MySQL事务_事务隔离级别_05

在默认情况下,MySQL自动提交事务,也就是执行一条语句后就会自动提交。如果要手动提交事务,需要使用以下语句关闭自动提交:

SET AUTOCOMMIT=0;

17、MySQL事务_事务隔离级别_06

事务支持保存点

MySQL还支持保存点(Savepoint)的概念,即在事务中创建一个保存点,可以在后续操作中回滚到这个保存点。保存点使用以下语句创建:

SAVEPOINT savepoint_name;

使用以下语句回滚到保存点:

ROLLBACK TO savepoint_name;

17、MySQL事务_事务_07

查看事务:

#查看当前正在进行的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
#查看当前锁定的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
#查看当前等锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

17、MySQL事务_事务_08

17、MySQL事务_事务_09

锁等待

17、MySQL事务_事务隔离级别_10

17、MySQL事务_commit_11

17、MySQL事务_commit_12

17、MySQL事务_commit_13

17、MySQL事务_事务_14

17、MySQL事务_commit_15

17、MySQL事务_commit_16

17、MySQL事务_死锁_17

事务隔离

事务隔离级别指的是在多个并发事务执行时,保证每个事务所见到的数据视图的隔离程度。MySQL 提供了四个标准隔离级别:

READ UNCOMMITTED(未提交读):在一个事务中,可以读取另一个未提交的事务中的数据。此级别存在最严重的问题,即脏读(Dirty Read)。

READ COMMITTED(提交读):一个事务只能读取另一个事务已经提交的数据。此级别避免了脏读,但仍可能出现不可重复读(Non-repeatable Read)。

REPEATABLE READ(可重复读):在同一事务中,多次读取同一个数据时,其值保持不变。此级别解决了不可重复读问题,但仍可能出现幻读(Phantom Read)。

SERIALIZABLE(可串行化):在这个级别下,所有的事务串行执行。这样可以避免脏读、不可重复读和幻读,但对性能的影响较大。

说明

读未提交(Read Uncommitted)隔离级别:在该级别下,即使一个事务还没有提交,其对数据的修改对于其他事务也是可见的。

示例:假设当前有两个事务 T1 和 T2,T1 执行以下语句:

set global tx_isolation=Read-Uncommitted;
#T1事务
BEGIN;
update students set name="lgw123" where stuid=2;
#T2事务
begin;
select * from students;

17、MySQL事务_事务隔离级别_18

17、MySQL事务_死锁_19

此时 T1 可能会读到 T2 已经插入的一行记录,即使 T2 还没有提交。

读提交(Read Committed)隔离级别:在该级别下,事务只能看见已经提交的事务所做的修改。

示例:假设当前有两个事务 T1 和 T2,T1 执行以下语句:

set global tx_isolation=Read-committed;
#T1事务
BEGIN;
update students set name="lgw123" where stuid=2;
#T2事务
begin;
select * from students;

17、MySQL事务_commit_20

此时 T1 只能看到已经提交的事务所做的修改,不能看到 T2 未提交的修改;可读取到提交数据,但未提交数据不可读,产生不可重复读,即可读取到多个提交数据,导致每次读取数据不一致;且T2如果需要更新该条数据,需要等T1提交后才可,否则才是锁等待

可重复读(Repeatable Read)隔离级别:在该级别下,每个事务第一次读取数据时,都会对其做一个快照,事务在本次读取过程中只能看到这个快照中的数据。

示例:假设当前有两个事务 T1 和 T2,T1 执行以下语句:

set global tx_isolation=Repeatable-Read; 默认隔离级别
#T1事务
BEGIN;
update students set name="lgw123" where stuid=2;
#T2事务
begin;
select * from students;

17、MySQL事务_事务_21

17、MySQL事务_事务隔离级别_22

17、MySQL事务_事务隔离级别_23

此时 T2只能看到第一次读取时的数据快照中的数据,即使 T1 在 T2 执行后修改了数据,T2 也无法看到 T1 的修改,直到 T2 结束。

串行化(Serializable)隔离级别:在该级别下,所有事务都按顺序依次执行,不存在并发的情况。

示例:假设当前有两个事务 T1 和 T2,T1 执行以下语句:

set global tx_isolation=SERIALIZABLE;

此时 T1 只有在 T2 执行完之后才能执行,不存在并发的情况。

READ COMMITTED和REPEATABLE READ两个隔离级别的区别主要在于锁定和可重复读方面。

READ COMMITTED级别下,事务只会锁定查询到的行,查询结束后就会释放锁定,这样可以避免长时间的锁定,但也会导致在同一事务内多次查询同一行数据时,可能会得到不同的结果,因为其他事务可能已经修改了这一行数据。

REPEATABLE READ级别下,事务会锁定查询的所有行,直到事务结束才会释放,这样可以保证在同一事务内多次查询同一行数据时,得到的结果都是一致的。但同时也会导致在同一事务内并发更新同一行数据时,可能会出现死锁的情况。

因此,如果应用程序对数据的一致性要求比较高,可以使用REPEATABLE READ隔离级别,否则可以使用READ COMMITTED隔离级别来提高并发性能。

MVCC和事务的隔离级别:

MVCC(多版本并发控制机制)只在REPEATABLE READ和READ COMMITTED两个隔离级别下工作。其他两个隔离级别都和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE则会对所有读取的行都加锁.。

指定事务隔离级别:

服务器变量tx_isolation指定,默认为REPEATABLE-READ,可在GLOBAL和SESSION级进行设置

SET tx_isolation=READ-UNCOMMITTED|READ-COMMITTED|REPEATABLEREAD|SERIALIZABLE

服务器选项中指定

vim /etc/my.cnf
[mysqld]
transaction-isolation=SERIALIZABLE

死锁:

两个或多个事务在同一资源相互占用,并请求锁定对方占用的资源的状态

死锁是指两个或多个事务互相持有对方所需资源而无法继续执行的一种情况。比如,事务A持有资源X,请求资源Y,而事务B持有资源Y,请求资源X,这样两个事务之间就形成了一个死锁。如果不解决死锁,这些事务将无法完成,从而导致系统崩溃或失效。

假设有两个事务T1和T2,操作的表为table,同时执行以下操作:

事务T1:UPDATE table SET num = num + 1 WHERE id = 1;
事务T2:UPDATE table SET num = num + 1 WHERE id = 2;
事务T1:UPDATE table SET num = num + 1 WHERE id = 2;
事务T2:UPDATE table SET num = num + 1 WHERE id = 1;

在以上操作中,事务T1和T2都试图更新id为1和2的行,但是它们的更新顺序是相反的,因此在执行过程中会发生死锁。例如,T1首先获取了id=1的行的锁,然后试图获取id=2的行的锁,而T2则首先获取了id=2的行的锁,然后试图获取id=1的行的锁,因此两个事务都等待对方释放锁,进入了死锁状态。

MySQL事务

文章目录

MySQL事务

一、事务的两种操作

1.手动提交事务

语句功能
start transaction; 或者 BEGIN;开启事务
commit;提交事务
rollback;回滚事务
  • 手动提交事务流程

2.自动提交事务

  • MySQL 默认每一条 DML(增删改)语句都是一个单独的事务,每条语句都会自动开启一个事务,语句执行完毕 自动提交事务,MySQL 默认开始自动提交事务
  • MySQL默认是自动提交事务
SHOW VARIABLES LIKE ‘autocommit’;查看autocommit状态
SET @@autocommit=off;将默认的自动提交事务改为手动提交事务

二、事务四大特性

特性含义
原子性每个事务都是一个整体,不可再拆分,事务中所有的 SQL 语句要么都执行成功, 要么都失败。
一致性事务在执行前数据库的状态与执行后数据库的状态保持一致。
隔离性事务与事务之间不应该相互影响,执行时保持隔离的状态.
持久性一旦事务执行成功,对数据库的修改是持久的。就算关机,数据也是要保存下来的.

三、事务隔离级别

  • 并发访问会导致的问题
问题说明
脏读一个事务读取到了另一个事务中尚未提交的数据
不可重复读一个事务中两次读取的数据内容不一致, 要求的是在一个事务中多次读取时数据是一致的.
幻读一个事务中,某一次的 select 操作得到的结果所表征的数据状态, 无法支撑后续的业务操作. 查询得到的数据状态不准确,导致幻读.
  • 四种隔离级别(隔离级别越高,效率越低
  • 查看隔离级别:select @@tx_isolation;
  • 设置事务隔离级别,需要退出 MySQL 再重新登录才能看到隔离级别的变化
set global transaction isolation level 级别名称; 
read uncommitted 读未提交 
read committed 读已提交 
repeatable read 可重复读 
serializable 串行化

以上是关于17MySQL事务的主要内容,如果未能解决你的问题,请参考以下文章

mysql 发生死锁问题请求帮助

减少InnoDB死锁发生的方法有什么?MySQL学习

在 haproxy 中的写入故障转移期间,正在进行的 mysql 事务会发生啥?

这种僵局会如何发生?

MySQL事务处理实现方法步骤

MySQL事务处理实现方法步骤