- 一:事务概述
1) 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
2)当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
事务的四个特性:ACID
1.原子性 aotmic
2.一致性 consistent
3.隔离性 isolaton
4.持久性 duration
- 二:隔离级别
1.隔离级别概述
事务隔离定义了数据库系统中一个操作产生的影响什么时候以哪种方式可以对其他并发操作可见。
即:主要影响的是并发事务之间的可见性
(1)未提交读Read Uncommitted
最低级别的隔离级别:意思就是即使一个更新语句没有提交,但是别的事务可以读到这个改变.这是很不安全的,可能会出现脏读。
(2)读提交 Read Committed
(3)可重复读 Repeatable Read
2.隔离级别修改SQL
(1) 查询mysql数据库系统级别的事务隔离级别
select @@global.tx_isolation
(2)InnoDB会话级别的事务隔离级别
SELECT @@tx_isolation
(3)修改数据库事务隔离级别
SQL SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
- 三.隔离级别VS读现象(Read phenomena)
举例说明
在表user 中有下列数据
mysql> select * from user; +----+----------+------+ | id | username | age | +----+----------+------+ | 1 | juzy | 20 | +----+----------+------+
1.脏读 dirty reads
当一个事务允许读取另外一个事务修改但未提交的数据时,就可能发生脏读(dirty reads)。
如下实例:事务1隔离级别设置为read uncommitted,事务2正在修改id=1的数据还没有提交,事务1读取到了这一数据。如果事务2回滚,那么事务1就获取到了脏数据
事务1
|
事务2 |
mysql> set session transaction isolation level read uncommitted; |
|
mysql> start transaction; mysql> update user set age=30 where id=1; |
|
mysql> select * from user where id =1; +----+----------+------+ | id | username | age | +----+----------+------+ | 1 | juzy | 30 | +----+----------+------+ |
2.不可重复读(non-repeatable reads)
在一次事务中,当一行数据获取两遍得到不同的结果表示发生了“不可重复读(non-repeatable read)”.
未提交读和提交读都有可能发生不可重复读现象。
事务1 | 事务2 |
mysql> select * from user where id =1; +----+----------+------+ | id | username | age | +----+----------+------+ | 1 | juzy | 20 | +----+----------+------+ |
|
mysql> update user set age=30 where id=1; |
|
mysql> select * from user where id =1; +----+----------+------+ | id | username | age | +----+----------+------+ | 1 | juzy | 30 | +----+----------+------+ |
3.幻读 (phantorm read )
在事务执行过程中,当两个完全相同的查询语句执行得到不同的结果集。这种现象称为“幻影读(phantom read)”
事务1 | 事务2 |
mysql> select * from user where age>=20; +----+----------+------+ | id | username | age | +----+----------+------+ | 1 | juzy | 20 | +----+----------+------+ |
|
mysql> insert into user(id,username,age)values(2,'yolanda',30); |
|
mysql> select * from user where age>=20; +----+----------+------+ | id | username | age | +----+----------+------+ | 1 | juzy | 20 | | 2 | yolanda | 30 | +----+----------+------+ |
各个隔离级别可能会出现的读现象
离级别 | 脏读(Dirty Read) | 不可重复读(NonRepeateable Read) | 幻读(Phantom Read) |
未提交读(Read uncommitted) | 可能 | 可能 | 可能 |
已提交读(Read committed) | 不可能 | 可能 | 可能 |
可重复读(Repeatable read) | 不可能 | 不可能 | 可能 |
可序列化(Serializable) | 不可能 | 不可能 | 不可能 |
不可重复读和幻读的区别
很多人容易搞混不可重复读和幻读,确实这两者有些相似。但不可重复读重点在于update和delete,而幻读的重点在于insert。
- 四.默认的隔离级别
目前mysql的默认隔离级别是RR,oracle的默认隔离级别是RC
且mysql的RR 级别下不会出现幻读。see http://www.ningoo.net/html/2008/mysql_innodb_transaction_isolation_level.html
- 五:隔离级别VS锁
在传统的数据库系统的实现中,一般实现不同等级的隔离性方法是使用锁定(lock)
1.锁
乐观锁(optimistic locking):乐观锁相信数据之间的数据竞争的概率是比较小的,因此尽可能的会直接做下去,知道提交的时候去锁定,但是有可能会遇到冲突。
一种可靠的乐观锁的实现是使用多版本控制(multi-version concurrency control),即在每一行加一个version属性,修改这一行时将version加1,写回数据库要检查当地前的version值是否还是获取时候的值,如果海华丝,说明在此期间没有修改,commit即可,如果不是,说明在此期间已经有修改了,当前事务获取的数据已过期,事务失败。
悲观锁(Pessimistic Concurrency Control):先取锁再访问
隔离级别 | 写入锁 | 读取锁 | 范围锁 |
未提交读 | |||
已提交读 | YES | ||
可重复读 | YES | YES | |
可序列化 | YES | YES | YES |
参考link:
[1]http://zh.wikipedia.org/wiki/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BA%8B%E5%8A%A1
[2]http://zh.wikipedia.org/wiki/%E4%BA%8B%E5%8B%99%E9%9A%94%E9%9B%A2
[3]https://www.byvoid.com/blog/rdbms-isolation-lock-concurrency
[4]http://tech.meituan.com/innodb-lock.html