事务(Transaction)是访问和更新数据库的程序执行单元;事务中可能包含一个或多个 sql 语句,这些语句要么都执行,要么都不执行。
读到其它事务为提交的数据mysql
同一个事务,select语句相同但读到数据不一样sql
同一个事务,select语句项目但读到数据行数不一样
不可重复读的重点是修改,幻读的重点在于新增或者删除。数据库
一个事务中,能够读取到其余事务未提交的变动并发
一个事务中,能够读取到其余事务已经提交的变动性能
一个事务中,直到事务结束前,均可以反复读取到事务刚开始看到的数据,不会发生变化
mysql的默认隔离级别是RR
RR和RC的区别是在一个事务中RR隔离级别的读到一张表的数据都是同样学习
即使每次读都须要得到表级共享锁,每次写都加表级排它锁,两个会话间读写会相互阻塞,会致使MySQL性能下降。spa
查看隔离级别:线程
SELECT @@tx_isolation;
事务ACID特性是如何实现的哪?日志
事务的原子性、隔离性、持久性都是为了实现数据一致性
InnoDB实现事务的回滚靠的就是undo_log
对数据进行修改会追加undo_log
对数据库的修改并不会当即修改磁盘中的数据表,而是先追加redo_log,再更新内存中数据(Write-ahead
logging,预写式日志),后续由master thread或者刷脏线程阶段性将这些数据刷到磁盘
这样阶段性的刷脏能够将多个IO merge成一个IO,也下降了访问延时,提供系统吞吐,当MySQL忽然宕机也不会致使数据丢失,可根据redo_log进行数据恢复
严格的隔离性对应Serializable(可串性化)隔离级别,在实际使用处于性能的考虑不多使用。
隔离性追求的是并发状况下事务之间互补影响
在对数据进行修改时,须要得到锁,在数据修改为功事务提交以后释放锁
MySQL有行锁和表锁,InnoDB使用的行锁,行锁比表锁锁定更少的资源,在大部分状况的性能更高
模拟并发更新致使死锁的状况:
在一个窗口链接mysql并执行如下操做code
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update tuser set age=20 where id_card=4; Query OK, 0 rows affected (0.12 sec) Rows matched: 0 Changed: 0 Warnings: 0
另外一个窗口链接mysql并执行
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update tuser set age=20 where id_card=4;
查看锁状况
mysql> select * from information_schema.innodb_locks; +-----------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+ | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | +-----------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+ | 2150479:671:3:2 | 2150479 | X | RECORD | `test`.`tuser` | PRIMARY | 671 | 3 | 2 | 1 | | 2150478:671:3:2 | 2150478 | X | RECORD | `test`.`tuser` | PRIMARY | 671 | 3 | 2 | 1 | +-----------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+ 2 rows in set, 1 warning (0.08 sec)
mysql> show engine innodb status;
Multi-Version Concurrency Control,即多版本的并发控制协议
MVCC解决了脏读、不可重复读、幻读
MVCC,多个版本的数据能够共存,主要是依靠数据的隐藏列(也能够称之为标记位)和 undo log。
每行数据都会多2列
create_time系统版本号
delete_time系统版本号
select
1.判断create_time, 行的系统版本号 <= 当前事务的系统版本号 2.判断delete_time, 行的删除版本未定义 || 大于当前事务版本号
update
插入一条新纪录,更新create_time 删除一条数据,并更新delete_time
insert
更新create_time
delete
更新delete_time
1.事务A执行begin开启事务,select查询时向系统申请一个版本号
2.事务B执行update更新了tuser表中id=4这一行数据的版本号
3.事务A select查询使用的仍是第一次select时使用的版本号,判断id=4这一行的版本号比当前版本号大,经过undo_log找到和当前版本号一致的数据,事务A二次查询结果时一致的,实现了事务的可重复读
MySQL做为一个开源数据库,被不少公司使用,在使用过程当中去深刻了解其内部原理是颇有必要的事情,知其然并知其因此然,学习是一个积累的过程,只要坚持就会有收获。