隔离级别引发问题实验

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_42453117/article/details/89390375

继续上篇博客 事务特性及隔离问题。
我们来做一个关于隔离级别的实验,将演示各个级别导致的隔离问题。
我们先打开两个MySQL窗口,来模拟并发操作。

  1. 脏读
    只有Read uncommitted级别才会发生脏读问题,所以将其中一个窗口的隔离级别设置为Read uncommitted。输入set transaction isolation level Read uncommitted;
    在MySQL5.5的64位版本中输入该段代码是无法修改隔离级别的,应该输入set session transaction isolation level read committed;修改隔离级别后,该窗口就被允许发生脏读。现在给这两个窗口命名一下,方便后续讲解,我们就令设置了事务隔离级别的窗口为B,另一个窗口为A。
    在A、B窗口分别开启一个事务,输入start transaction;现在同时查看两个用户的表数据
    在这里插入图片描述
    现在在A窗口完成转账操作,输入
update account set money = money - 200 where name = 'aaa';
update account set money = money + 200 where name = 'bbb';

然后查询表数据
在这里插入图片描述
转账操作成功执行。
此时在B窗口进行查询
左边是A窗口,右边是B窗口
会发现,B窗口读取到了A窗口未提交的数据,此时在A窗口进行回滚操作,再次查询表数据
在这里插入图片描述
两个用户的表数据都回到了原来的状态,但是B窗口在之前查询数据的时候,是确认了aaa账户转账了200元给bbb账户的,而此时转账操作却被回滚了,钱又相当于转回给了aaa账户,此时就造成了bbb账户的经济损失,这就是脏读现象。

  1. 不可重复读
    修改事务隔离级别,在B窗口输入set transaction isolation level Read committed;
    这次我们重复刚才的操作,两边同时开启事务,然后在A窗口更新数据,接着两边都查询一下表数据
    在这里插入图片描述
    此时会发现,在A窗口未提交之前,B窗口的数据不会改变。这时候就避免了脏读,但是它会导致不可重复读。我们让A窗口提交,然后再次到B窗口查询
    在这里插入图片描述
    此时B窗口的表数据发生了变化,读取到了A窗口提交的结果,需要注意的是,B窗口在同一个事务中却读取到了两次不同的表数据,这就是不可重复读。
  2. 虚读
    修改事务隔离级别,在B窗口输入set transaction isolation level Repeatable read;
    在A、B窗口分别开启一个事务,在A窗口转账提交,B窗口连续地查询,会发现B窗口是不会读取到A提交的结果的,这样就避免了不可重复读。
    在A窗口输入更新语句
 update account set money = money-500 where name = 'bbb';
 update account set money = money+500 where name = 'ccc';

然后提交A窗口的操作,查询两边的表数据
在这里插入图片描述
发现即使A窗口提交了操作,B窗口的表数据仍然不会被改变,证实了刚才的结论,但是该隔离级别会导致虚读的产生。很遗憾的是,虚读无法为大家举例了,因为虚读发生的概率是非常低的,但是方法还是给大家介绍一下。
在A窗口插入一条数据,输入insert into account values (4,'ddd',1000);,然后在B窗口进行表数据查询,如果查询到了A窗口插入的数据,说明发生了虚读,但很显然,这个现象并没有发生,所以图我就不贴了。

  1. 最后介绍一下最后一个事务隔离级别
    演示一下Serializable的串行处理效果。
    将B窗口的级别设置为Serializable,然后在A、B窗口同时开启一个事务,此时在B窗口执行查询语句,然后在A窗口插入或更新一条数据,输入insert into account values(5,'eee',1000);当你按回车键执行语句时,你会发现,A窗口并没有马上执行sql语句,而是阻塞了。那这是为什么呢?因为该级别是最高隔离级别,采取串行处理方法,在一个用户操作该数据库时,不允许别的用户操作。

那么接下来请注意了,在JDBC程序中如何控制数据库的隔离级别呢?
在Connection接口中定义了五个字段,它们就是用来控制对应的隔离级别的,只需要调用setTransactionIsolation(int level)方法并将对应的字段传入,即可达到控制隔离级别的效果。如果不设置隔离级别,将采用数据库默认级别,Oracle和MySQL数据库的默认级别是什么还记得吗?不记得的话就再次阅读一下我的上一篇博客。
还有一个需要注意的地方,在MySQL5.5的64位版本中,输入set transaction isolation level代码并不能成功修改事务隔离级别,这又是为什么呢?因为在MySQL5.0的规范中就规定,该条语句必须加上一个关键字session,也就是说,想要成功修改,你得输入set session transaction isolation level才能成功修改。

展开阅读全文

C#分布式事务隔离级别问题?如何解释不同的隔离级别,结合案例。

04-01

[code=C#]rnusing System;rnusing System.Collections.Generic;rnusing System.ComponentModel;rnusing System.Data;rnusing System.Drawing;rnusing System.Text;rnusing System.Windows.Forms;rnusing System.Data.SqlClient;rnusing System.Transactions;rnrnnamespace MyFriendrnrn /*rn * --隔离级别rn 级别一 read uncommitted System.Transactions.IsolationLevel.ReadUncommitted --未提交读rnrn 级别二 read committed System.Transactions.IsolationLevel.ReadCommitted --提交读rnrn 级别三 repeatable read System.Transactions.IsolationLevel.RepeatableRead --可重复读rnrn 级别四 serializable System.Transactions.IsolationLevel.Serializable --可串行读 rn*/rn public partial class frmIsolationLevel : Formrn rn public frmIsolationLevel()rn rn InitializeComponent();rn rn private static string GetConnectionString(int i)rn rn if (i == 1)rn return "Data Source=.;Initial Catalog=MyFriend;User ID=sa;Password=123456";rn elsern return "Data Source=.;Initial Catalog=student;User ID=sa;Password=123456";rn rnrn private void button1_Click(object sender, EventArgs e)rn rn string str1 = "insert into depart values('市场部3',19,'1982-02-03')";rn string str2 = "insert into info values('拉灯3','078889897878','13989889899','阿富汗捣蛋部队','999','技术部')";rnrn SqlConnection cn1 = new SqlConnection(GetConnectionString(1)); //连接库1rn cn1.Open();rn TransactionOptions op = new TransactionOptions();rn //op.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; //提交读rn op.IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead; //提交读rnrn using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, op)) //创建事务代码块rn rn SqlCommand cmd1 = new SqlCommand(str1, cn1);rn int rowsUpdated1 = cmd1.ExecuteNonQuery();rn if (rowsUpdated1 > 0)rn rn SqlConnection cn2 = new SqlConnection(GetConnectionString(1));//连接库2.rn cn2.Open();rn SqlCommand cmd2 = new SqlCommand(str2, cn2);rnrn int rowsUpdated2 = cmd2.ExecuteNonQuery();rn if (rowsUpdated2 > 0)rn rn ts.Complete();rn MessageBox.Show("事务提交完成!");rn rn cn2.Close();rn rn rn cn1.Close();rn rnrn rnrn//*************db如下:rnrn[/code][code=SQL]--Create DataBase MyFriendrnuse MyFriendrngornCreate table info --个人信息表.rn(rn id int identity(1,1) Constraint PK_Id Primary key,rn name char(8) not null,--姓名rn telephone char(12),--电话号码rn mobilephone char(11),--手机号码rn company varchar(30),--公司名称rn position varchar(12),--职位rn depart varchar(20)--部门 rn)rnrnCreate table depart --部门表rn(rn DName varchar(20) Constraint PK_DName primary key, --部门名称rn DNum varchar(8) not null, --部门人员数量rn DDate datetime, --创建日期rn)rn--建立外键.rnalter table infornadd Constraint FK_Name foreign key(depart)rnreferences depart(DName)rnrninsert into depart values('行政部',7,'2002-2-8')rninsert into depart values('技术部',88,'2002-2-7')rninsert into depart values('服务部',2000,'2002-2-8')rninsert into depart values('财务部',9,'2002-2-23')rnrninsert into info values('李小梦','037189897878','13989889899','河南正德集团','CEO','服务部')rninsert into info values('李超勇','097489897878','13989889899','青海超永集团','XO','技术部')rninsert into info values('马英九','078889897878','13989889899','台湾国民集团','OOO','财务部')rnrnrnupdate info rnset name='乘龙',telephone='0378-6754789'rnwhere id=3rndelete from depart where dName='吃喝部'rnselect * from departrnselect * from info [/code] 论坛

没有更多推荐了,返回首页