MySQL事务

2022-02-16 21:23:53 浏览数 (1)

什么是事务?

事务就是保证一组数据库操作要么全部成功,要么全部失败。MySQL中,事务的支持是在引擎层实现的。InnoDB支持事务,MyISAM不支持事务,这也是InnoDB逐渐取代MyISAM的原因之一。

事务有哪些特性?

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

为什么需要隔离级别?

数据库有多个事务在同时执行的时候,可能会出现脏读、不可重复读、幻读等问题,为了解决这些问题,便出现了隔离级别。

  • 脏读:事务T1将某一值进行修改,此时事务T2读取到该值,但是事务T1后面因为其他操作产生了回滚,此时事务T2读到的就是一条无效的数据,也就是脏数据
  • 不可重复读:简而言之就是一次事务中,多次读取同一个值,该值前后内容不一致,举例:事务T1读取某一个值为20,事务T1紧接着去做其他事情,此时事务T2将该值修改为30,当事务T1处理完其他事情再来查询的时候查到该值为30,此时就产生了不可重复读问题(也就是说在我们的同一个事务中不能重复读取某个值)
  • 幻读:简而言之就是一次事务中,前后多次读取到的数据总量不一致,举例:事务T1在开始读取到的数据总量为100条,事务T1此时去做其他事情,此时事务T2将该数据新增了100条,当事务T1处理完其他事情再来查询数据总量为200条,此时就产生了幻读问题

MySQL事务隔离级别

  • 读未提交:一个事务还未提交,它的变更可以被其他事务看到
  • 读提交:一个事务提交以后,它的变更才可以被其他事务看到
  • 可重复读:一个事务执行过程中看到的数据始终保持和事务启动时看到的数据一致
  • 串行化:对于同一行记录写会加写锁,读会加读锁。当出现读写锁冲突时后一个事务必须等待前一个事务执行完成,才能继续执行。

每一种隔离级别可以解决对应的问题,如下:

脏读

不可重复读

幻读

读未提交

未解决

未解决

未解决

读提交

解决

未解决

未解决

可重复读

解决

解决

未解决

串行化

解决

解决

解决

MySQL事务隔离级别如何实现?

串行化隔离级别是通过直接加速的方式避免并行访问。

读未提交是直接返回记录上的新值。

其他隔离级别的实现是通过创建视图的方式来实现的,在访问时以视图的逻辑结果为准,只不过每种隔离级别创建视图的时机不同:

  • 读提交:视图是在每个SQL语句开始执行的时候创建
  • 可重复读:视图是事务启动的时候创建,整个事务都使用整个视图

上述的视图不是指的我们create view的那个视图,而是InnoDB用到的一致性视图。

MySQL事务隔离级别设置

1.通过配置文件my.cnf修改

代码语言:javascript复制
[mysqld]
transaction-isolation = REPEATABLE-READ
transaction-read-only = OFF

2.通过SQL语句执行

代码语言:javascript复制
-- 查看当前隔离级别
show variables like 'transaction_isolation';

-- 针对当前会话设置隔离级别
set session transaction isolation level read committed ;

-- 设置全局事务隔离级别,对已连接的会话不生效
set global transaction isolation level read committed ;

MySQL的回滚日志?

MySQL在执行更新的时候除了会记录redo log以外,还会记录一条回滚操作到undo log,通过回滚日志可以得到前一个状态的值。

假设一个值1按照顺序改成了2、3、4,会有如下回滚日志:

在查询这条记录的时候,不同时刻启动的事务会有不同的视图,在视图A、B、C中这个记录的值分别为1、2、4,同一条记录在系统中可以存在多个版本,这成为数据库的多版本控制(MVCC)。

关于MVCC的详细细节我们在后续了解完锁以后一起说,这样update语句的所有操作基本就全了(锁 事务 日志)。

MySQL的回滚日志什么时候删除?

系统判断没有比这个回滚日志更早的视图的时候(也就是没有事务再用到这些回滚日志时),回滚日志就会被删除。

长事务会存在很多老的视图,事务可能会访问数据库里的任何数据,因此这个事务提交前,数据库里面用到的回滚记录都必须保留,这就会导致回滚日志占用大量的存储空间。

因此如果系统中存在过多的长事务,会导致数据库存储空间增加迅速,并且也会占用锁资源,将有可能拖垮整个库。

MySQL如何启动事务?

1.set autocommit=1;

该方式下事务会自动提交。

代码语言:javascript复制
-- 显示开启事务
begin/start transaction ;

-- 提交事务
commit; 

-- 提交事务并自动启动下一个事务
-- 对于事务频繁使用的系统,可以减少begin/start transaction的一次交互。
commit work and chain ;

-- 回滚事务
rollback;

2.set autocommit=0;

该命令会将线程的自动提交关闭,只要执行一个select语句便开启事务,并且事务不会自动提交,必须手动commit和rollback。

推荐使用第一种方式set autocommit=1的方式,这种方式事务会自动提交,避免忘记手动commit带来的长事务。

0 人点赞