文章目录
事务
讨论事务的前提,是有并发的连接。用户定义的一系列操作,要么都做要么都不做,可回滚不可分割。因此,单条指令也是一个事务,如果事务只需要一条指令,就不用begin / commit
sql
begin/start transaction
commit
rollback
隔离级别
为了保证MySQL中事物的隔离性,多个事务共同操作一块资源时,可能MySQL串行地去执行这些事务。也即串行化,是MySQL中最高级别的隔离。
但是串行执行的效率较低,MySQL为了做到高性能,适当地破坏了逻辑上地一致性,所有写操作都必须是串行执行 ,提出了四种隔离界别,按照性能从高到低:
读未提交
sql
set transaction isolation level read uncommited;
读:不做任何处理
写:自动加X锁
读已提交
sql
set transaction isolation level read commited;
读:mvcc 读取最新版本地行数据
写:自动加X锁
可重复读
sql
set transaction isolation level repeatable read;
读:(InnoDB默认的隔离级别) mvcc 读取事务开始前版本的行数据
写:自动加X锁
可串行化
不同级别的隔离异常
脏读 : (读未提交)
一个事务读到另一个未提交事务修改的数据
不可重复读:(读未提交,读已提交)
一个事务两次读取同一个数据的结果不同
幻读 :(读未提交,读已提交,可重复读)
一个事务两次读取同一个范围的结果不同,破坏完整约束一致性,当前读和快照读不一致
**在可重复读的级别上解决幻读问题:**手动加锁
sql
select * from account_t where id > 3 for update
# for update
MVCC
实现非锁的一致性读
MVCC是怎么实现的:
readview
m_ids
创建read view时,已启动但是未提交的事务id列表
min_trx_id
创建read view时,已启动但未提交的最小事务id
max_trx_id
创建read view时,预分配给下一个未开启事务的id
create_trx_id
创建read view的事务id
读已提交:每次读取数据时,生成新的read view
可重复读:启动事务时,生成新的read view,一直使用直到事务提交,或事务回滚
快照读:可见版本
select * from table where ?
当前读:最新版本
select * from table where ? lock in share mode 查+读锁
select * from table where ? for update 查+写锁
insert into table values(...) DML语句
update table set ? where ?
delete from table where ?
锁
全局锁
表级锁
行级锁(Innodb)
死锁
死锁的原因:并发事务在执行的过程中,因争夺锁资源而造成的一种互相等待现象。
相反加锁顺序死锁:
不同表加锁顺序相反;
相同表不同行加锁顺序相反
解决:调整加锁顺序
锁冲突死锁:
RR隔离级别下,插入意向锁与gap锁冲突死锁
解决:降低隔离级别到RC