大家好,又见面了,我是你们的朋友全栈君。[b]事务不同引发的状况:[/b]
脏读(Dirty reads)
一个事务读取另一个事务尚未提交的修改时,产生脏读
很多数据库允许脏读以避免排它锁的竞争。
不可重复读(Nonrepeatable reads)
同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。
幻读(Phantom reads)
同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻像读。
[b]数据库操作的隔离级别[/b]
未提交读(read uncommitted)
提交读(read committed)
重复读(repeatable read)
序列化(serializable)
[b]oracle默认隔离级别[/b]read committed (statement level serialization)
每一个语句,在语句开始时,会获取一个此刻的数据快照。
一个事务有多条语句,如果语句之间存在其它完成的事务,
这可能引起不可持续读和幻读。
新建一个测试表books:
name,code,price三个字段
添加两条测试数据
[img]http://dl2.iteye.com/upload/attachment/0096/6188/19e41b31-81f9-3a08-bd58-e047843614d5.jpg[/img]
使用pl/sql和java程序模拟并发
[i]不允许脏读测试:[/i]
程序段首先查询code是qqq的书的价格
//获取连接 省略
pstat = conn.prepareStatement("select price from books where code='qqq'");
rs = pstat.executeQuery();
while(rs.next()){
System.out.println("price:"+rs.getDouble(1));
}
close();
输出结果:price:15.0
然后pl/sql执行更新
update books set price=18 where code='qqq';
[color=orange]!pl/sql设置成手动更新,不自动更新[/color]
在执行上面java查询代码
输出仍是price:15.0,说明读不到pl/sql中未提交的执行结果,即不允许脏读
pl/sql 执行
commit;
在执行java查询:
输出结果:price:18.0
会有不可重复读何幻读的现象发生就不用测试了吧,
这两种现象都是针对提交后事物的读引起的,read commited隔离级别是允许对提交后
的事物进行读的。
[i]隔离级别:重复读(repeatable read)[/i]
这个不允许脏读,不可重复读,但是会有幻读现象。
这个oracle不支持,不好测试。
理解的话就是如果一条查询语句查询的内容有其它事物正在更新的时候,这
查询处于等待状态,直到先前事物提交更新后,才会执行本条查询。也就是
查询的时候也会有锁,需要等待并发的事物释放锁。然后自己获取到锁,执行
自己事物。这样查询也加锁,并发性更低
select … for update 就是这样可以避免不可重复读的发生
[i]隔离级别:serializable [/i]
这个就更严格了,事物执行是一个一个的。一个事务中的语句共享同一个数据快照(在事务开始时存在的数据)。
是事物级别的,脏读,不可重复读,幻读根本就没有机会发生。
前面像read committed都是语句级别的,以语句为单元。
比如
read committed一个事物A有a(select),b(select),c(update)三条语句
当A事物执行a,b的时候,若有B事物执行更新操作,是有可能的
因为a,b是不加锁的
写个例子:
//获取连接和关闭连接代码 省略
//不自动提交
conn.setAutoCommit(false);
/**
* a 查询
*/
pstat = conn.prepareStatement("select price from books where code='qqq'");
rs = pstat.executeQuery();
while(rs.next()){
//输出 price:25.0
System.out.println("price:"+rs.getDouble(1));
}
close();
/**
* 暂停一会,用pl/sql执行B事务
* update books set price=15 where code='qqq';
* commit;
*/
Thread.sleep(10000);
/**
* 如果这里再执行a查询的话,和第一次查询结果就不一样,因为中间有B事务的提交更新
* 修改,这也是不可重复读
*/
//b 更新
pstat = conn.prepareStatement("update books set price=price+10 where code='qqq'");
pstat.executeUpdate();
close();
//c 查询
pstat = conn.prepareStatement("select price from books where code='qqq'");
rs = pstat.executeQuery();
while(rs.next()){
//输出 还是price:25.0 ,因为B事务的干预
System.out.println("price:"+rs.getDouble(1));
}
close();
//提交事务
conn.commit();
if(conn != null){
conn.close();
}
上面执行的顺序,
事务B是在A的执行过程中执行的
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/141148.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...