数据库并发访问会出现以下4种问题:
1、第一类丢失更新:事务B嵌套在事务A中,事务B已经更新,之后事务A更新失败,A回滚,丢失了B的更新。(支持事务的数据库不会出现此问题)
2、脏读:读到其他事务还未提交的数据。3、不可重复读:在同一事务中,两次读取的数据不一致。(被其他事务修改了)
4、幻读:两次读取的记录数不一致。(针对插入和删除操作)
设置数据库的事务隔离级别可以防止以上问题:
隔离级别 | 脏读(Dirty Read) | 不可重复读(NonRepeatable Read) | 幻读(Phantom Read) | 说明(MSSQL2000中测试) |
读未提交(Read uncommitted) | 可能 | 可能 | 可能 | |
读已提交(Read committed) | 不可能 | 可能 | 可能 | 1、保证查询到的是其他事务已经提交的数据。(Update/Delete/Insert语句优先) 2、测试语句如下,先执行事务A,再执行事务B: 事务A: begin tran SET TRAN ISOLATION LEVEL READ COMMITTED --update ql_车号 set 车号=车号 +'1' --insert into ql_车号 values('aaa33') delete from ql_车号 where 车号= 'aaa11' select * from ql_车号 waitfor delay '00:00:03' commit 事务B: begin tran SET TRAN ISOLATION LEVEL READ COMMITTED select * from ql_车号 --waitfor delay '00:00:03' --select * from ql_车号 --waitfor delay '00:00:04' commit |
可重复读(Repeatable read) | 不可能 | 不可能 | 可能 | 1、保证在同一事务中,前后读出的数据是一致的。(Select语句优先) 2、先事务A读取数据,事务A完毕前,执行事务B修改数据.事务B中使用Update或Delete语句,若有符合条件的数据,则等待事务A执行完成再执行事务B;若没有符合条件的数据(即不会影响原来的数据),则事务A、B各自执行。 3、对事务B中的Insert语句不起作用。(所以会出现幻读) 4、测试语句如下,先执行事务A,再执行事务B: 事务A: begin tran SET TRAN ISOLATION LEVEL REPEATABLE READ select * from ql_车号 waitfor delay '00:00:03' select * from ql_车号 commit 事务B: begin tran SET TRAN ISOLATION LEVEL REPEATABLE READ --update ql_车号 set 车号=车号 +'1' delete from ql_车号 where 车号= 'aaa'
select * from ql_车号 commit |
可串行化(Serializable ) | 不可能 | 不可能 | 不可能 |
数据库一般的默认隔离离级别是“读已提交”,默认的事务隔离级别下:Insert,update ,delete下的是X锁, 会等待事务完成。通常情况下可以把隔离级别设为Read Commited,它能避免脏读,而且有较好的并发性能。尽管它会导致不可重复读、虚读和第二类更新丢失等问题,在可能出现这类问题的个别场合可以由应用程序釆用悲观锁或乐观锁来控制。
MySQL的默认事务隔离级别是REPEATABLE_READ,ORACLE、SQL Server、DB2和PostgreSQL的默认事务隔离级别是READ_COMMITED。