序言:以下内容讲的是mysql数据库的原理,是mysql内部实现的,基本不用人工代码干预
数据库事务四大特性-ACID
事务的:原子性、一致性、分离性、持久性
事物(transaction)是由一些列操作序列构成的执行单元,这些单元要么都做,要么不做,是一个不可分割的工作单元。
数据库事物的四个基本性质(ACID)
1.原子性(Atomicity)
指的是事物中包含的所有操作要么全做,要么全不做(all or none)。
例如银行取款事务分为2个步骤(1)存折减款(2)提取现金。不可能存折减款,却没有提取现金。2个步骤必须同时完成或者都不完成。
2.一致性(consistency)
在事物开始以前,数据库处于一致性的状态,事物结束后,数据库也必须处于一致性的状态。
拿银行转账来说,一致性要求事务的执行不应改变A、B 两个账户的金额总和。如果没有这种一致性要求,转账过程中就会发生钱无中生有,或者不翼而飞的现象。事务应该把数据库从一个一致性状态转换到另外一个一致性状态。
3.隔离性(Isolation)
分离性指并发的事务是相互隔离的。即一个事务内部的操作及正在操作的数据必须封锁起来,不被其它企图进行修改的事务看到。假如并发交叉执行的事务没有任何控制,操纵相同的共享对象的多个并发事务的执行可能引起异常情况。
对于任何一对事务T1和T2,在事务T1看来,T2要么在T1开始之前执行,要么在T1完成之后才开始执行,这样,每个事务都感觉不到系统中有并发事务执行。
4.持久性(Durability)
持久性意味着当系统或介质发生故障时,确保已提交事务的更新不能丢失。即一旦一个事务提交,DBMS保证它对数据库中数据的改变应该是永久性的,即对已提交事务的更新能恢复。持久性通过数据库备份和恢复来保证。
数据库事务并发问题
多个事务同时访问数据库时候,会发生下列 问题,包括3类数据 问题(脏读,不可重复读,幻读)
1,脏读(dirty read)
A事务读取B事务尚未提交的更改数据,并在这个数据基础上操作。如果B事务回滚,那么A事务读到的数据根本不是合法的,称为脏读。
2,不可重复读(unrepeatable read)
A事务读取了B事务已经提交的更改(或删除)数据。比如A事务第一次读取数据,然后B事务更改该数据并提交,A事务再次读取数据,两次读取的数据不一样。
3,幻读(phantom read)
A事务读取了B事务已经提交的新增数据。注意和不可重复读的区别,这里是新增,不可重复读是更改(或删除)。
数据库事务并发问题—解决措施:锁机制–4种隔离级别
共享锁和排它锁
为了解决并发问题,数据库系统引入锁机制。
基本的封锁类型有两种: 排它锁(Exclusive locks 简记为X锁) 和 共享锁(Share locks 简记为S锁)。
排它锁又称为写锁。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其它事务在T释放A上的锁之前不能再读取和修改A。
共享锁又称为读锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其它事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
隔离级别
在运用 排他锁 和 共享锁 对数据对象加锁时,还需要约定一些规则,例如何时申请 排他锁 或 共享锁、持锁时间、何时释放等。称这些规则为 隔离级别。
数据库事务的隔离级别有4种,由低到高分别为Read uncommitted 、Read committed 、Repeatable read 、Serializable
Read Uncommitted【读未提交数据】:允许所有事务读取未被其他事务提交的数据修改。会导致脏读、不可重复读和幻读的问题的出现。
Read Committed【读已提交数据】:只允许事务读取已经被其他事务提交的数据修改。Oracle和sql server默认的级别,可以避免脏读,但不可重复读和幻读问题仍然会出现。
Repeatable Read【可重读】:是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。但幻读问题未解除。
Serializable【可串行化】:最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。一般通过共享读锁实现。在这个级别,可能导致大量的超时现象和锁竞争。
数据库中,通常默认隔离级别是“可重读”,在默认的事务隔离级别下:insert,update,delete用的是排他锁, 会等待事务完成。通常情况下可以把隔离级别设为Repeatable Read,它能避免脏读、不可重复读,而且有较好的并发性能。
如何解决mysql的幻读问题
为了数据库的良好性能,而又不想使用高的隔离级别(Serializable【可串行化】)解决幻读问题,采用mvcc或者next-key 锁解决幻读问题
1,MVCC ( Multi-Version Concurrency Control )多版本并发控制
在快照读的情况下(即普通的select),mysql InnoDB就是通过mvcc来解决幻读问题:通过为每一行记录添加两个额外的隐藏的值来实现MVCC,这两个值一个记录这行数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。但是InnoDB并不存储这些事件发生时的实际时间,相反它只存储这些事件发生时的系统版本号。这是一个随着事务的创建而不断增长的数字。每个事务在事务开始时会记录它自己的系统版本号。每个查询必须去检查每行数据的版本号与事务的版本号是否相同。让我们来看看当隔离级别是REPEATABLE READ时这种策略是如何应用到特定的操作的
InnoDB会根据以下两个条件检查每行记录:
InnoDB只会查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的.
行的删除版本要么未定义,要么大于当前事务版本号(这可以确保事务读取到的行,在事务开始之前未被删除),
只有条件1、2同时满足的记录,才能返回作为查询结果.
2,next-key 锁
在当前读的情况下(update , insert ,delete ,select xx from xx for update , in share mode)情况下,用next-key 锁解决幻读问题,具体参考我的另外一篇文章《mysql innodb的死锁问题》