重新认识Mysql之事务那些事

dilipy 2019-11-03

(一)什么是事务?

是一组原子性的SQL查询,或者说是一个独立的工作单元。事务内的语句,要么就全部执行,要么就全都不执行。

场景模拟:

用户A给用户B转账1000元

用户A - 1000元
用户B + 1000元

以上操作,要么全部执行成功,要么全部执行失败,不会出现用户A扣钱,用户B加钱这种现象发生.

(二、)事务的四大特性

  1. 原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
  1. 一致性(Consistency)
表示一个事务内有一个操作失败了,所有更改过的数据都必须会滚到修改前的状态
  1. 隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

4.持久性(Durability)

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

(三、)事务的隔离级别

数据库事务的隔离级别有4种,由低到高分别为Read uncommitted(未提交读)、Read committed(读提交)、Repeatable read(重复读)、Serializable(序列化)。

但是在事务的并发操作中可能会出现脏读,不可重复读,幻读

1. Read uncommitted(未提交读)

引发现象:==脏读==

事务B可以读取到事务A未提交的数据.

场景模拟:

职员小A的工资是3000,但是发工资时,老板按错了数字,按成了30000元,但是事务还没有提交,就在这个时候,小A去查询了工资,以为涨工资了非常开心,但是老板发现不对,及时回滚数据,再重新改成3000进行提交:

场景分析:

这个情况就是脏读,小A看到的工资是30000万,但实际还是3000元,因为他看到的是老板还没提交的数据.

解决方案:

Read committed(读提交),能解决掉脏读的问题

2. Read committed(读提交)

事务B必须要等待事务A提交后才能读取数据,一个事务从开始到提交结束之前,所做的任何修改对其他事务都是不可见的.所以也称为
不可重复读

场景模拟:

职员小A准备去商场购物(卡余额3000元),当他准备进行买单时(小A事务开启),收费系统检测到小A的卡主有3000元可以支付,就在这时,小A的女朋友需要把钱全部转出去充当家用,并提交(女朋友事务在小A前),当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了,结果小A购物失败....

场景分析:
这就是读提交,事务A在对数据进行更新操作时,事务B的读操作需要等待事务A更新操作提交完成后,才能读取数据,可以解决脏读问题。

但是在本场景中,收费系统中一个事务范围,两次相同的查询,却获取到了不同的结果,这就是==不可重复读(两次执行一样查询,结果却不同)==

解决方案:

Repeatable read(重复读) 来解决.

3.Repeatable read(重复读)

重复读:在事务开启进行读数据时,不允许修改操作。

补充:Mysql默认事务隔离级别为:Repeatable read

场景模拟:

第二个月,职员小A又出去购物(卡里余额3000元),当他准备买单时(事务开启,不允许其他事务更新操作),收费系统检测他卡中余额3000元,他的女朋友又想转出这3000元作为家用,但是转出失败(无法更新修改),收费系统扣款成功,小A顺利完成了购物!

场景分析:

重复读,虽然可以解决不可重读问题,但是重复读对应的是修改(Update)操作,还是可能中途会出现插入(Insert)操作,会产生出幻读问题.

幻读场景模拟:

职员小A,去查询消费记录(事务开启),发现消费了1000元,卡中还剩2000元,开始打印消费清单(事务提交),但是在打印清单的刚刚,老板发工资了,新增了3000元(insert了一条记录),发现清单上的余额是5000元,跟之前的查询的记录不对,这就是幻读.

幻读:指的是一个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行(phantom row)

重点:Mysql InnoDB存储引擎通过Next-Key Locking解决了幻读的问题

解决方案:

非 InnoDB引擎 幻读解决方案 Serializable(序列化)

Serializable(序列化)

Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。Serializable 在读取的每一行数据上都进行了加锁.

(四、事务操作命令及实战)

1. 查看数据库引擎是否支持事务(Innodb支持?)

show engines

2. 查看Mysql默认储存引擎

show variables like '%storage_engine%';

3.创建事务

//开启事务
start transaction

//开启事务
begin

//二者等价

4.提交事务

COMMIT 会提交事务,并使已对数据库进行的所有修改成为永久性的

//提交
commit 

//提交
commit work

//二者等价

//提交后开启一个新事务
commit and chain

5.回滚事务

回滚会结束用户的事务,并撤销正在进行的所有未提交的修改

//回滚
rollback

//回滚
rollback work

//二者等价

6.Mysql自动提交模式

//查看当前自动提交
show variables like 'autocommit'

//禁止自动提交
SET AUTOCOMMIT=0  

//开启自动提交
SET AUTOCOMMIT=1

7.事务还原点

//在事务中创建一个保存点
savepoint identifier

//将事务回滚到标记点
rollback to identifier

实战案例:

//开启事务
begin;

//更新
update users set name = '我是第一次的名字' where id = 2;

//保存点ts1
savepoint ts1;

//更新
update users set name = '我是第二次的名字' where id = 2;

//保存点ts2
savepoint ts2;

//查询
select * from users where id =2;

//回滚到ts1
rollback to ts1;

8.InnoDB锁的问题

在InnoDB储存引擎中,start transaction 开启事务会造成一个隐式的unlock tables 执行

实战案例:

ClientA:
    //写锁
    lock table users write;

ClientB:
    //查询,卡住等待锁释放
    select name from users where id = 2 ;
    
ClientA:
    //更新数据
    update users set name = '17ns' where id = 2;
    
ClientB:
    //查询卡住中
    
ClientA:
    //开启事务,隐式执行了unlock tables
    begin;
    
ClientB:
    //获得数据

实战图

重新认识Mysql之事务那些事

尾:

以上就是事务操作的基本性质主要特征就是ACID(原子性,一致性,隔离性,持久性),在一些重要的场景使用事务会提高程序的可靠性,使数据能够正确地提交到数据库当中。

相关推荐

方志朋 / 0评论 2020-04-17