本文共 3574 字,大约阅读时间需要 11 分钟。
基本概念
是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。和程序比较:
在关系数据库中,一个事务可以是一条或多条SQL语句,也可以包含一个或多个程序。 一个程序通常包含多个事务。事务的特性(ACID)
多用户数据库:允许多个用户同时使用的数据库(订票系统)
不同的多事务执行方式:并发执行带来的问题:
并发操作带来的数据不一致性包括
记号:W(x)写数据x R(x)读数据x
并发控制机制的任务:
并发控制的主要技术
封锁:封锁就是事务T在对某个数据对象(例如表、记录等)操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象
确切的控制由封锁的类型决定
排它锁(X锁,exclusive locks)、共享锁(S 锁,share locks)
排它锁又称写锁,对A加了排它锁之后,其他事务不能对A加 任何类型的锁(排斥读和写)
共享锁又称读锁,对A加了共享锁之后,其他事务只能对A加S锁,不能加X锁(只排斥写)Innodb的意向锁主要用户多粒度的锁并存的情况。比如事务A要在一个表上加S锁,如果表中的一行已被事务B加了X锁,那么该锁的申请也应被阻塞。如果表中的数据很多,逐行检查锁标志的开销将很大,系统的性能将会受到影响。为了解决这个问题,可以在表级上引入新的锁类型来表示其所属行的加锁情况,这就引出了“意向锁”的概念。
举个例子,如果表中记录1亿,事务A把其中有几条记录上了行锁了,这时事务B需要给这个表加表级锁,如果没有意向锁的话,那就要去表中查找这一亿条记录是否上锁了。如果存在意向锁,那么假如事务A在更新一条记录之前,先加意向锁,再加X锁,事务B先检查该表上是否存在意向锁,存在的意向锁是否与自己准备加的锁冲突,如果有冲突,则等待直到事务A释放,而无须逐条记录去检测。事务B更新表时,其实无须知道到底哪一行被锁了,它只要知道反正有一行被锁了就行了。 说白了意向锁的主要作用是处理行锁和表锁之间的矛盾,能够显示“某个事务正在某一行上持有了锁,或者准备去持有锁”。在运用X锁和S锁对数据对象加锁时,需要约定一些规则:封锁协议(Locking Protocol)
何时申请X锁或S锁 持锁时间、何时释放对封锁方式制定不同的规则,就形成了各种不同的封锁协议。
常用的封锁协议:三级封锁协议、 两段锁协议 三级封锁协议在不同程度上解决了并发问题,为并发操作的正确调度提供一定的保证。1、一级封锁协议
事务T在修改数据R之前,必须先对其加X锁,直到事务结束(commit/rollback)才释放。 一级封锁协议可以防止丢失修改 如果是读数据,不需要加锁的,所以它不能保证可重复读和不读“脏”数据。2、 二级封锁协议
在一级封锁协议的基础(写要加X锁,事务结束释放)上,增加事务T在读入数据R之前必须先对其加S锁,读完后即可释放S锁。(读要加S锁,读完即释放) 二级封锁协议除了可以防止丢失修改,还可以防止读脏数据 由于读完数据即释放S锁,不能保证不可重复读3、三级封锁协议:
在一级封锁协议基础上增加事务T在读取数据R之前必须先对其加S锁,直到事务结束后释放。 三级封锁协议除了可以防止丢失修改和读脏数据外,还防止了不可重复读。 三级封锁协议的主要区别是什么操作需要申请锁,何时释放锁。封锁协议越高,一致性程度越高。加锁和解锁分为两个阶段进行。在事务执行过程中,随时都可以锁定,锁只有在执行commit或rollback时才会释放,并且所有的锁都是在同一时刻被释放。
MySQL 的 InnoDB 存储引擎采用两段锁协议,会根据隔离级别在需要的时候自动加锁,并且所有的锁都是在同一时刻被释放,这被称为隐式锁定。
脏读"、“不可重复读"和"幻读”,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大。
MYSQL常看当前数据库的事务隔离级别:show variables like ‘tx_isolation’;
1、读未提交 (Read Uncommitted)
最低的隔离等级,允许其他事务看到没有提交的数据,会导致脏读。2、读已提交 (Read Committed)
被读取的数据可以被其他事务修改,这样可能导致不可重复读。也就是说一个事务所做的修改在提交之前对其它事务是不可见的。该等级也是 SQL Server 默认的隔离等级。3、可重复读(Repeatable Read)
一个事务中多次读取相同的记录,结果是一致的,可避免脏读、不可重复读。MYSQL默认是REPEATABLE-READ 。
4、串行化(Serializable)
所有事务一个接着一个的执行,这样可以避免幻读 (phantom read),对于基于锁来实现并发控制的数据库来说,串行化要求在执行范围查询的时候,需要获取范围锁,如果不是基于锁实现并发控制的数据库,则检查到有违反串行操作的事务时,需回滚该事务。5、总结
读未提交: 一个事务还没提交时,它做的变更就能被别的事务看到。 读提交: 一个事务提交之后,它做的变更才会被其他事务看到。 可重复读 : 一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。 串行化: 顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。 四个级别逐渐增强,每个级别解决一个问题,事务级别越高,性能越差,大多数环境(Read committed 就可以用了)隔离级别 | 读数据一致性 | 脏读 | 不可重复读 | 幻影读 |
---|---|---|---|---|
未提交读 | 最低级别 | √ | √ | √ |
提交读 | 语句级 | × | √ | √ |
可重复读 | 事务级 | × | × | √ |
可串行化 | 最高级别 | × | × | × |
读未提交 无锁
读已提交 MVCC(Multi-Version Concurrency Control, MVCC)多版本并发控制
可重复读
MVCC只工作在REPEATABLE READ和READ COMMITED隔离级别下。 MVCC最大的作用是: 实现了非阻塞的读操作,写操作也只锁定了必要的行.可序列化 读加共享锁,写加排他锁,读写互斥。使用的悲观锁的理论。
参考:
转载地址:http://qerwi.baihongyu.com/