1.mysql的事务
什么是事务?维基百科的定义:事务是数据库管理系统(DBMS)执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成
事务的四大特性:ACID。即原子性,一致性,隔离性,持久性
原子性:每个事务都是不可分割的最小单位,就像原子一样
一致性:数据库从一种状态转化成另一种状态
隔离性:事务对其他事务是隔离的不可见的,它通过锁机制实现
持久性:事务提交成功, 数据修改就是永久的
事务的隔离级别:
隔离级别与脏读、幻读、不可重复读的关系
隔离级别 | 脏读 | 不可重复读 | 幻读 |
READ UNCOMMITED (读未提交) | 允许 | 允许 | 允许 |
READ COMMITED (读提交) | 不允许 | 允许 | 允许 |
REPEATABLE READ (可重复读) | 不允许 | 不允许 | 允许 |
SERIALIZABLE (串行化) | 不允许 | 不允许 | 不允许 |
2.锁机制
相比其他数据库而言,mysql的锁机制比较简单,而且不同的存储引擎支持不同的锁机制
MyISAM 和 Memory 存储引擎使用的是表级锁,BDB 引擎使用的是页级锁,也支持表级锁。由于 BDB 引擎基本已经成为历史,因此就不再介绍了。
InnoDB 存储引擎既支持行级锁,也支持表级锁,默认情况下使用行级锁。
所谓表级锁,它直接锁住的是一个表,开销小,加锁快,不会出现死锁的情况,锁定粒度大,发生锁冲突的概率更高,并发度最低。
所谓行级锁,它直接锁住的是一条记录,开销大,加锁慢,发生锁冲突的概率较低,并发度很高 。
所谓页级锁,它是锁住的一个页面,在 InnoDB 中一个页面为 16KB ,它的开销介于表级锁和行级锁中间,也可能会出现死锁,锁定粒度也介于表级锁和行级锁中间,并发度也介于表级锁和行级锁中间。
仅仅从锁的角度来说,表级锁更加适合于以查询为主的应用,只有少量按照索引条件更新数据的应用,比如大多数的 web 应用。
行级锁更适合大量按照索引条件并发更新少量不同的数据,同时还有并发查询的应用,比如一些在线事务处理系统,即 OLTP 。
3.innodb锁
innodb与myisam的相当大的两点不同在于:1.支持事务,2.采用行级锁
表级锁没有与行级锁的实现差别就很大,而事务的引入也带来了很多新问题,尤其是事务的隔离性,与锁的机制息息相关
数据库实现事务隔离的方式可以分为两种:
1.在操作数据之前,对其加锁,防止其他事务对数据进行修改。但这个需要事务串行化
2.不加锁,特点时间内对数据进行快照,产生多个版本的数据库,即mvcc
4.innodb的锁类型:
innodb实现了下面两种类型的锁:共享锁,排它锁
如果一个事务请求的锁模式与当前的锁兼容,InnoDB 就将请求的锁授予该事务,如果两者是冲突的,那么该事务就要等待锁释放。
对于 update、delete、insert 语句,InnoDB 会自动给设计到的数据集加排他锁即 X。
对于 select 语句,InnoDB 不会加任何锁。
我们可以使用如下语句来显式的给数据集加锁
共享锁(S):select * from t1 where .... lock in share mode;
排它锁 (X) :select * from t1 where ... for update;
5.死锁
什么情况下会产生死锁:
死锁是指两个或两个以上的进程在执行过程中 , 因争夺资源而造成的一种互相等待的现象 , 若无外力作用 , 它们都将无法推进下去 . 此时称系统处于死锁状态或系统产生了死锁, 这些永远在互相等待的进程称为死锁进程 . 表级锁不会产生死锁 . 所以解决死锁主要还是针对于最常用的 InnoDB的行锁
mysql 处理死锁的方式:
等待,直到超时 (innodb_lock_wait_timeout=50s)。
发起 死锁检测 ,主动回滚一条事务,让其他事务继续执行( innodb_deadlock_detect=on )
检测到死锁之后, 选择插入更新或者删除的行数最少的事务回滚,基 于 INFORMATION_SCHEMA.INNODB_TRX 表中的 trx_weight 字段来判断。
6.间隙锁
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(NEXT-KEY)锁。
7.行锁升级为表锁
InnoDB 行级锁是通过给索引上的索引项加锁来实现的, InnoDB 行级锁只有 通过索引条件检索数据,才使用行级锁 ;否则,就是在 没有使用索引的情况下InnoDB就会使用表级锁 (共享锁不会有这个情况)