java学习笔记:事务的隔离级别
事务的隔离级别
----
1.事务的特性:ACID
(1)原子性:强调事务的不可分割,Automatic
(2)一致性:事务的执行的前后,数据的完整性保持一致, Consistence。
(3)隔离性:一个事务在执行的过程中,不应该受到其他事务的干扰, Isolation。
(4)持久性:事务一旦结束,数据就持久到数据库中, Durability。
什么问题导致的隔离性?
因为数据库在设计的时候底层必须保证多线程。由于在多个线程之间来回切换导致了隔离性特点
2.如果不考虑事务的隔离性,会引发安全性问题。
(1)读问题:三类
A.脏读:一个事务读到了另一个事务未提交的数据。
B.不可重复读:一个事务读到了另一个事务已经提交(update)的数据。引发一个事务中的多次查询结果不一致。
C.虚读/幻读:一个事务读到了另一个事务已经提交的(insert)数据,导致多次查询的结果不一致。
(2)解决读问题:设置事务的隔离级别
A.设置事务的隔离级别
read-uncommitted:脏读、不可重复读、虚读都可能发生。
read-committed:避免脏读,但是不可重复读和虚读都有可能发生。
repeatable-read:避免脏读和不可重复读,但是虚读有可能发生。
serializable:避免脏读,不可重复读和虚读(串行化的,不可能出现事务并发访问)
B.安全性:serializable > repeatable-read > read-committed > read-uncommitted
C.效率:serializable < repeatable-read < read-committed < read-uncommitted
MySQL的默认隔离级别:repeatable-read
Oracle的默认隔离级别:read-committed
查询隔离级别:select @@tx_isolation;
设置隔离级别为read committed: set session transaction isolation level read committed;
3.演示脏读的发生
步骤一:分别开启两个窗口A,B;(双击sqlyog启动它,连接成功,这就是窗口A;再双击sqlyog启动它,连接成功,这就是窗口B。)
步骤二:分别查询两个窗口的隔离级别:
select @@tx_isolation;
步骤三:设置A窗口的隔离级别为read uncommitted
set session traction isolation level read uncommitted;
B窗口的隔离级别为mysql的默认级别,即repeatable read
步骤四:在两个窗口中分别开启事务:
start transaction;
步骤五:在B窗口中转账操作:
update account set money = money - 1000 where name='jack';
update account set money = money + 1000 where name='rose';
**** 在B窗口中没有提交事务的!!!
步骤六:在A窗口中进行查询:
已经转账成功!!!(脏读:一个事务中读到了另一个事务未提交的数据)
4.演示避免脏读,不可重复读发生
步骤一:分别开启两个窗口A,B:
步骤二:分别查询两个窗口的隔离级别:
select @@tx_isolation
步骤三:设置A窗口的隔离级别为read committed;
set session transaction isolation level read committed;
步骤四:在两个窗口中分别开启事务:
start transaction;
步骤五:在B窗口中完成转账的操作:
update account set money = money - 1000 where name='守义';
update account set money = money + 1000 where name='凤儿';
**** 在B窗口中没有提交事务!!!
步骤六:在A窗口中进行查询:
没有转账的结果!!!(已经避免了脏读)
步骤七:在B窗口中提交事务!!!
commit;
步骤八:在A窗口中进行查询:
转账成功!!!(不可重复读:一个事务读到了另一个事务已经提交的update的数据,导致一次事务中多次查询结果不一致.)
假如系统做单独一个统计功能: 统计今天的订单信息,这件事情一下子还做不完,
先查询订单信息(晚上23点50分),计算很多其他的数据。。。。,再次查询订单信息(晚上23点52分)
5.演示避免不可重复读
步骤一:分别开启两个窗口A,B:
步骤二:分别查询两个窗口的隔离级别:
select @@tx_isolation
步骤三:设置A窗口的隔离级别为repeatable read;
set session transaction isolation level repeatable read;
步骤四:在两个窗口中分别开始事务:
start transaction;
步骤五:在B窗口中完成转账的操作:
update account set money = money - 1000 where name='守义';
update account set money = money + 1000 where name='凤儿';
***** 在B窗口没有提交事务!!!
步骤六:在A窗口中进行查询:
没有转账成功!!!(已经避免脏读)
步骤七:在B窗口提交事务!!!
commit;
步骤八:在A窗口进行查询:
转账没有成功!!(避免不可重复读)
步骤九:在A窗口中结束事务,再重新查询.
6.演示隔离级别为serializable
步骤一:分别开启两个窗口A,B:
步骤二:分别查询两个窗口的隔离级别:
select @@tx_isolation
步骤三:设置A窗口的隔离级别为serializable;
set session transaction isolation level serializable;
步骤四:在两个窗口中分别开启事务:
start transaction;
步骤五:在B窗口中完成一个insert操作:
insert into account values (null,'芙蓉',10000);
***** 事务没有提交!!
步骤六:在A窗口中进行查找:
没有任何结果!!!(不可以事务并发执行的)
步骤七:在B窗口中结束事务!
7.幻读
(1)幻读的定义:所谓幻读,是指事务A读取与搜索条件相匹配的若干行。事务B以插入或删除行等方式来修改事务A的结果集,然后再提交。
幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也 修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一 样。
(2)解决幻读的方法:一般解决幻读的方法是增加范围锁RangeS,锁定检锁范围为只读,这样就避免了幻读。简单来说,幻读是由插入或者删除引起的。
(3)不可重复读(虚读)和幻读的差别:
大致的区别在于不可重复读是由于另一个事务对数据的更改所造成的,而幻读是由于另一个事务插入或删除引起的。
从总的结果来看, 似乎两者都表现为两次读取的结果不一致. 但如果你从控制的角度来看, 两者的区别就比较大:
对于前者, 只需要锁住满足条件的记录。对于后者, 要锁住满足条件及其相近的记录。