「前言」文章内容大致是MySQL事务管理。
「归属专栏」MySQL
「主页链接」个人主页
「笔者」枫叶先生(fy)
事务的概念
MySQL同一时刻可能存在大量事务,如果不对这些事务加以控制,在执行时就可能会出现问题。
每条事务至少一条SQL或者很多条的SQL,这样如果大家都访问同样的表数据,在不加保护的情况,就绝对会出现问题。甚至,因为事务由多条SQL构成,那么,也会存在执行到一半出错或者不想再执行的情况,那么已经执行的怎么办?
因此一个完整的事务并不是简单的SQL集合,事务还需要满足如下四个属性:
上面的四个属性简称ACID:
为什么会出现事务
在 MySQL 中只有使用了Innodb数据库引擎的数据库或表才支持事务, MyISAM不支持
通过以下命令查看MySQL的数据库引擎,查看哪些引擎支持事务
show engines;
说明:
事务常见的提交方式有两种,分别是自动提交和手动提交
查看事务的提交方式:
show variables like 'autocommit';
注:ON表示自动提交被打开,值为OFF表示自动提交被关闭,即事务的提交方式为手动提交
可以用SET来改变MySQL的自动提交模式
SET AUTOCOMMIT=0; --禁止自动提交 SET AUTOCOMMIT=1; --开启自动提交
注:设置为0表示关闭自动提交,相当于将事务提交方式设置为手动提交
为了便于演示,需要将MySQL的隔离级别设置成读未提交,也就是把隔离级别设置的比较低,方便看到实验现象
隔离级有:(隔离级别依次提高,读未提交隔离级别最低)
设置最低的隔离级别:
set global transaction isolation level read uncommitted;
注意:设置全局隔离级别后当前会话的隔离级别不会改变,只会影响后续与MySQL新建立的连接,因此需要重启终端才能看到会话的隔离级别被成功设置
重启客户端之后,再进行登录,查看如下:
然后创建测试表
create table if not exists account( id int primary key, name varchar(50) not null default '', blance decimal(10,2) not null default 0.0 )ENGINE=InnoDB DEFAULT CHARSET=UTF8;
测试1
启动两个终端,两个终端都各启动一个事务(右边不启动事务也行),启动事务使用以下命令任意一个:
begin; -- or start transaction;
启动事务之后,查询该表是没有数据的
注:这里事务提交方式为自动提交
左终端中的事务使用savepoint命令创建一个保存点,该命令用于设置一个保存点
savepoint 保存点名字;
在左终端中插入一条数据,在右终端中就能查看到左终端的事务向表中插入的记录
左终端中的事务使用savepoint命令创建一个保存点,然后继续向表中插入一条记录,这时在右终端中也能看到新插入的这条记录(读未提交)
左终端中的事务使用rollback命令回滚到事务
rollback to 保存点; -- 事务回滚到该保存点 rollback; -- 默认回滚到事务的最开始
事务回滚到保存点s2,这时右终端在查看表中数据时就看不到刚才插入的第二条记录了
左终端中的事务直接使用rollback命令回滚到事务最开始,右边的终端查询数据为空
使用commit命令,可以提交事务(代表一个事务结束),提交事务后就不能回滚了
注意:提交事务之后就不能回滚了,再次rollback也无法回滚
上面是事务操作的正常情况,而事务更多是为了应对非正常的情况,比如MySQL客户端突然崩溃,不小心关闭等等
演示1(体现事务的原子性)
目的:证明事务未commit,客户端崩溃,MySQL自动会回滚(隔离级别设置为读未提交,事务提交方式为自动提交)
两个终端都各启动一个事务,表中事先有一条数据(右边不启动事务也行)
左终端中的事务向表中插入一条记录,由于隔离级别是读未提交,因此在右终端中能够查询到插入的这条记录
左边的客户端异常退出ctrl + \(没有提交事务)
结果是MySQL会自动让事务回滚到最开始,这时右终端中就看不到之前插入的记录了
演示2(体现事务的持久性)
目的:证明事务commit了,即使客户端崩溃,MySQL数据不会在受影响,数据已经持久化(已经保存到磁盘),(隔离级别依旧设置为读未提交,事务提交方式为自动提交)
两个终端都各启动一个事务(右边不启动事务也行)
左终端中的事务向表中插入一条记录,由于隔离级别是读未提交,因此在右终端中能够查询到插入的这条记录
左终端进行提交事务,然后再异常退出
右终端中仍然可以看到之前插入的记录,因为事务提交后数据就被持久化了
即使是事务自动提交关闭了,只要commit了,数据依旧就被持久化了,下面实验3进行验证
演示3(验证实验)
目的:证明begin操作会自动更改提交方式,不会受MySQL是否自动提交影响
关闭自动提交
set autocommit = 0;
左终端中启动一个事务并向表中新插入一条记录(右边也可以启动一个事务),由于隔离级别是读未提交,因此在右终端中能够查询到新插入的这条记录
左终端进行提交事务,然后再异常退出,右终端中仍然可以看到之前插入的记录,因为事务提交后数据就被持久化了
上述说明:使用begin或start transaction·命令启动的事务,都必须要使用commit命令手动提交,数据才会被持久化,与是否设置autocommit无关
演示4
目的:证明单条SQL与事务的关系
左右两边的终端都关闭自动提交,右边不关也行(右边不影响操作)
set autocommit = 0;
不启动事务,直接删除一条数据,由于隔离级别是读未提交,右边的终端也能看到结果
执行完单条SQL语句后,左边的客户端直接异常退出;而右边终端被删除的数据被回滚回来了
左边的终端打开自动提交,右边不影响操作
set autocommit = 1;
不启动事务,直接删除一条数据,由于隔离级别是读未提交,右边的终端也能看到结果
执行完单条SQL语句后,左边的客户端直接异常退出,右边的数据没有发生变化,即左边终端的操作没有被回滚
实验结果说明:实际我们之前一直都在使用单SQL事务,只不过autocommit默认是打开的,因此单SQL事务执行后自动就被提交了
上述实验结论
事务操作注意事项
隔离级别:(依次提高)
认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读,即一个事务执行时,如果多次 select,可能得到不同的结果
隔离级别基本都是通过锁实现的,不同的隔离级别,锁的使用是不同的。常见有,表锁,行锁,读锁,写锁,间隙锁(GAP),Next-Key锁(GAP+行锁)等
查看全局隔级别
select @@global.tx_isolation;
查看当前会话隔离级别
select @@session.tx_isolation;
还可以使用以下命令查看当前会话的隔离级别
select @@tx_isolation;
设置当前会话隔离级别
set session transaction isolation level 隔离级别;
例如,给当前会话设置串行化
set session transaction isolation level serializable;
注:设置当前会话的隔离级别只会影响当前会话,新起的会话依旧采用全局的隔离级
设置全局隔离级别
set global transaction isolation level 隔离级别;
比如设置全局可重复读
注意:设置全局隔离级别会影响后续的新会话,但是不会影响当前会话,如果需要让全局隔离级别生效,需要重启该客户端
下面进行实验演示,演示四个隔离级别
启动两个终端,将隔离级别都设置为读未提交,然后查看表中数据
set session transaction isolation level read uncommitted;
左右两个终端各启动一个事务,左边终端对表中数据进行修改,左边终端的事务没有提交右边终端的事务可以看到修改的数据
说明:
启动两个终端,将隔离级别都设置为读提交,然后查看表中数据
两个终端各自启动一个事务,左终端进行对表中数据修改,在左终端事务未提交之前,右终端的事务看不到另一个事务的对数据的修改结果
只有当左终端中的事务提交后,右终端中的事务才能看到修改后的数据
说明:
启动两个终端,将隔离级别都设置为可重复读,然后查看表中数据
两个终端各自启动一个事务,左终端中的事务所作的修改在没有提交之前,右终端中的事务无法看到
并且当左终端中的事务提交后,右终端中的事务仍然看不到修改后的数据
只有当右终端中的事务提交事务之后,再查看表中数据,此时才能看到表中数据
说明:
下面演示MySQL的可重复读是没有幻读问题
启动两个终端,将隔离级别都设置为可重复读,然后查看表中数据
然后两个终端各自启动一个事务,左终端向表中插入新数据并提交事务,右终端中的事务仍然看不到新插入的数据(证明没有幻读问题)
启动两个终端,将隔离级别都设置为串行化,然后查看表中数据
然后两个终端各自启动一个事务,如果这两个事务都对表进行的是读操作,那么这两个事务可以并发执行,不会被阻塞
果这两个事务中有一个事务要对表进行写操作,那么这个事务就会立即被阻塞
直到右边终端事务提交了之后,左终端的事务才能对表进行修改操作
说明:
隔离级别总结如下:
事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务
成功提交的结果时,数据库处于一致性状态。
--------------------- END ----------------------
「 作者 」 枫叶先生 「 更新 」 2023.9.7 「 声明 」 余之才疏学浅,故所撰文疏漏难免, 或有谬误或不准确之处,敬请读者批评指正。