一、事务是什么
事务是逻辑上的一组操作,要么都执行,要么都不执行。
sql语句如下:
# 开启事务
START TRANSACTION;
# 多条 SQL 语句
SQL1,SQL2...
## 提交事务
COMMIT;
二、事务的特性(ACID)
原子性(Atomicity):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;(执行完成)
一致性(Consistency):执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;(数据一致)
隔离性(Isolation):一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;(相互不影响)
持久性(Durability):一个事务被提交之后。它对数据库中数据的改变是持久的。(持久化更改)
三、并发事务带来的问题
脏写:对于同一行数据,一个事务对该行的的更新操作覆盖了其他事务对该行数据的更新操作。更新丢失的本质上是写操作的冲突,解决办法是让每个事务按照串行的方式执行,按照一定的顺序依次进行写操作。
脏读:一个事务读取了另外一个事务未提交的数据,后面这个事务回滚了所以查到的就是脏数据;脏读本质上是读写操作的冲突,解决办法是先写后读,也就是写完之后再读取。
不可重复读:同一个事务,使用相同的查询语句,在不同时刻读取的结果数据不一致。不可重复度的本质也是读写操作的冲突,解决的方法是先读后写,也就是读完之后在写。
幻读:一个事务两次读取的数据结果集数量不同,幻读本质是读写操作的冲突,解决办法是先读后写,也就是读完再写。
不可重复读重点在于更新与删除,而幻读重点在于插入操作。
四、事务隔离级别
READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
READ-COMMITTED(读取已提交):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
REPEATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
SERIALIZABLE(可串行化):最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
总结一下:
解决幻读的方法:
(1)串行化
(2)快照读:可重复读的情况下,使用MVCC机制(多版本并发控制)
(3)当前读:可重复读的情况下,使用 Next-Key Lock 进行加锁,Next-Key Lock 是行锁(Record Lock)和间隙锁(Gap Lock)的结合,行锁只能锁住已经存在的行,为了避免插入新行,需要依赖间隙锁。
(4)表锁 :在可重复读的事务级别下,给事务操作的这张表添加表锁。
五、锁分类
1、死锁
四个必要条件:
(1)互斥,当资源被一个线程使用(占有)时,别的线程不能使用。
(2)不可剥夺,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
(3)请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
(4)循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了环路等待。
A欠B100块钱,B欠C一百块钱,C欠A一百块。A说C还我才能还B,B说A还我才能还C,C 说B还我才能还A。
破坏上述任一条件,可解除死锁。
2、mysql锁分类
如图:
由于 MVCC 的存在,对于一般的 SELECT 语句,InnoDB 不会加任何锁。