1、事务的四大特性
原子性,隔离性,持久性,一致性
原子性(Atomicity): 语句要么全执行,要么全不执行,是事务最核心的特性,事务本身就是以原子性来定义的;实现主要基于undo log
一致性(Consistency): 事务追求的最终目标,一致性的实现既需要数据库层面的保障,也需要应用层面的保障
隔离性(Isolation): 保证事务执行尽可能不受其他事务影响;InnoDB默认的隔离级别是RR(可重复读 repeatable read),RR的实现主要基于锁机制(包含next-key lock)、MVCC(包括数据的隐藏列、基于undo log的版本链、ReadView)
持久性(Durability): 保证事务提交后不会因为宕机等原因导致数据丢失;实现主要基于redo log和双写缓冲
2、事务并发引起的三大问题(同一个事务两次读取的结果不一致)
脏读:一个事务读取到了其他事务未提交的数据,导致两次读取结果不一致
不可重复读:一个事务读取到了其他事务已提交的数据(update和delete),导致两次读取结果不一致
幻读:一个事务读取到了其他事务插入的数据,导致两次读取结果不一致
3、事务的隔离级别
读未提交(RU),事物A和事物B,事物A未提交的数据,事物B可以读取到,容易出现脏读
读已提交(RC),事物A和事物B,事物A提交的数据,事物B才能读取到,解决了脏读问题,一个事务读取了其他事务已提交的数据会出现不可重复读问题(oracle默认的隔离级别)
可重复读(RR),事务A和事务B,事务A提交之后的数据,事务B读取不到 - 事务B是可重复读取据,解决了不可重复读的问题,
串行化(serializable),事务A和事务B,事务A在操作数据库时,事务B只能排队等待,解决一切问题
4、Innodb是支持事务的,默认的隔离级别是RR(不需要用串行化就能解决所有问题,提高了并发性)
5、Innodb是运用了MVCC的核心思想
我可以查到在我这个事务开始之前已经存在的数据,即使它在后面被修改或者删 除了。在我这个事务之后新增的数据,我是查不到的。
(1)一个事务能看到数据库的版本
第一次查询之前的版本
本事务修改的版本
(2)一个事务不能看见的数据库版本
在本事务第一次查询之后创建的事务(事务id大于本事务)
活跃的(未提交)的事务的修改
MVCC的效果是建立一个快照,同一个事务无论查询多少次都是相同的结果
MVCC的实现原理:
DB_TRX_ID,插入或更新行的最后一个事务的事务ID,事务编号是自动 递增的(创建版本)。
DB_ROLL_PTR,回滚指针(删除版本)。
MVCC的查找规则:只能创建版本小于当前版本事务的数据,能查到删除版本大于当前事务的数据
5、Read view(可见性视图)
每个事务都维护一个自己的read view ,其中包括当前系统最大的事务id,活跃的事务id,本次事务的id
1、从数据的最早版本开始判断(undo log) 1、数据版本的trx_id = creator_trx_id,本事务修改,可以访问
2、数据版本的trx_id < min_trx_id(未提交事务的最小ID),说明这个版本 在生成ReadView已经提交,可以访问
3、数据版本的trx_id > max_trx_id(下一个事务ID),这个版本是生成 ReadView之后才开启的事务建立的,不能访问
4、数据版本的trx_id 在min_trx_id和max_trx_id之间,看看是否在m_ids中。 如果在,不可以。如果不在,可以。
5、如果当前版本不可见,就找undo log链中的下一个版本。
5.1RC与RR Read View的区别
RR中Read View是事务第一次查询的时候建立的。 RC的Read View是事务每次查询的时候建立的。
6、mysql中innodb锁的基本类型,myisam只支持表锁
共享锁(S锁,读锁),排它锁(X锁,写锁),意向共享锁(表锁),意向排他锁(表锁)
共享锁可以重复获取,多读事务可以共享一把锁
排他锁是一个事务获取这行数据的排他锁,其他事务就不能对这行数据加共享锁和排他锁,
意向锁共享锁是在一个事务对一行数据加了共享锁,就会在这个表上加一个意向共享锁,意向排它锁也是如此,意向锁是为了提高锁的效率的,意向锁是数据库自己维护的,
当需要向一张表加表锁的时候,如果没有意向锁需要判断是否有行锁,加了意向锁,就可以直接判断表里面是否加了行锁
innodb的行锁是通过锁住索引来实现的
根据锁的算法又分为记录锁和间隙锁
当查询的数据命中的时候是用记录锁
当查询的数据没有命中或者是一段范围的使用的是间隙锁
临键锁是间隙锁加记录锁
7 查看锁信息
show status like 'innodb_row_lock%' -- 查看行锁
-- Innodb_row_lock_current_waits正在等待锁的数量
-- Innodb_row_lock_time从系统启动到现在锁定的总时间长度,单位是ms
-- Innodb_row_lock_time_avg 每次平均等待说话的时间
-- Innodb_row_lock_time_max从系统启动到现在等待最长的一次所花的时间
-- Innodb_row_lock_waits 从系统启动到现在总共等待的次数
select * from information_schema.INNODB_TRX -- 当前所有运行的事务和语句
select * from information_schema.INNODB_LOCKS -- 当前出现的锁
select * from information_schema.INNODB_LOCK_WAITS -- 锁等待的对应关系
如果有事务长时间持有锁不释放,可以先kill掉这个事务对应的线程id,就是INNODB_TRX中对应的trx_mysql_thread_id
8 死锁的避免