悲观锁:悲观并发控制实际上是“先取锁再访问”,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数据。悲观锁大多数情况下依靠数据库的锁机制实现。每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。由于数据的及时锁定,在数据提交时候就不会出现冲突,可以省去很多恼人的数据冲突处理。缺点就是你必须要始终有一条数据库连接,就是说在整个锁定到最后放开锁的过程中,你的数据库联接要始终保持住。与悲观锁相对的,我们有了乐观锁。乐观锁一开始也说了,就是一开始假设不会造成数据冲突,在最后提交的时候再进行数据冲突检测。
乐观锁:乐观锁采取了宽松的加锁机制。大多是基于数据版本( Version )记录机制实现。 质上,悲观锁和乐观锁都是为了解决丢失更新问题或者是脏读。
乐观锁和悲观锁是来控制进程对数据库的操作,避免出现丢失更新,肮脏数据,不可重复的读取,虚读问题。在实际的业务逻辑中,是采用事物的隔离(根据事物和需求有四种隔离级别)和锁来达到数据的统一问题。
A:原子性(Atomicity)
事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。
B:一致性(Consistency)
事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
C:隔离性(Isolation)
一个事务的执行不能被其他事务干扰。
D:持续性/永久性(Durability)
一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。
发事务执行时,需要阻止这三种现象中的一种或多种发生
脏读:读取另一个事务未提交的数据
不可重复读:当前事务已经读取的数据记录,被其他事务修改或删除,结果集前后不一样
幻影读:其他事务插入了新的数据,当前事务以相同的查询条件,在那个事务插入数据之前和之后查询数据,得到的数据记录的条数不一样。
事务隔离级别:
read uncommitted 读未提交:会脏度,会不可重复读。
read committed 读提交:不会脏读,会不可重复读。
Repeatable read 重复读:不会不可重复读,因为事务A 在两次读取表T中的数据时,事务B如果企图更改表T中的数据(细节到事务A读取数据)时,就会被阻塞,知道事务A提交! 这样就保证了,事务A两次读取的数据的一致性。(同一行数据),锁定了行。一个事务所读取的数据记录不允许被其他事务所修改。
会幻读,repeatable read可以防止事务B对数据进行修改,但是事务B却可以向表T中插入新的数据。
Serializable序列化:
Serializable是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。
不可重复读和幻读的区别:
不可重复读的重点是修改:
同样的条件, 你读取过的数据, 再次读取出来发现值不一样了
幻读的重点在于新增或者删除
同样的条件, 第1次和第2次读出来的记录数不一样
1) "不可重复读" 是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可
能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改
。原始读取不可重复。如果只有在作者全部完成编写后编辑人员才可以读取文档,则可以避免该问题
要避免这种情况,通常可以用 set tran isolation level repeatable read 来设置隔离级别,这样事务A 在两次读取表T中的数据时,事务B如果企图更改表T中的数据(细节到事务A读取数据)时,就会被阻塞,知道事务A提交! 这样就保证了,事务A两次读取的数据的一致性。
2)幻觉读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么
,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。例如,一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主复本时,发现作者已将未编辑的新材
料添加到该文档中。如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。
还是上面的例子,事务A要两次读取表T的中数据,虽然设置 repeatable read 可以防止事务B对数据进行修改,但是事务B却可以向表T中插入新的数据。如何防止这个问题,我们可以考虑设置最高的事务隔离级别 set tran
isolation level serializable。于是乎,事务B就只能乖乖的等待事务A的提交,才能想表T中插入新的数据,从而避免了幻读!
避免不可重复读需要锁行就行
避免幻影读则需要锁表
不同事务的隔离性看有没有上锁
√: 可能出现 ×: 不会出现
脏读 |
不可重复读 |
幻读 |
|
Read uncommitted |
√ |
√ |
√ |
Read committed |
× |
√ |
√ |
Repeatable read |
× |
× |
√ |
Serializable |
× |
× |
× |
select * from v$version;
insert into t(id,name)values(1,'1111')
SELECT s.sid, s.serial#,
CASE BITAND(t.flag, POWER(2, 28))
WHEN 0 THEN 'READ COMMITTED'
ELSE 'SERIALIZABLE'
END AS isolation_level
FROM v$transaction t
JOIN v$session s ON t.addr = s.taddr AND s.sid = sys_context('USERENV', 'SID');
set transaction isolation level read uncommitted; 报错
ORA-02179:有效选项:isolation level{serializable|read committed}
Oracle明确支持ANSI/ISO SQL92中定义的serializable和read committed两种事务隔离级别
Oracle默认的隔离级别是read committed。