首页 新闻 会员 周边 捐助

C#事务处理问题,高手请进,大伙都给点意见,感激不尽

1
悬赏园豆:50 [已关闭问题] 关闭于 2010-09-03 12:48
SqlConnection Connection = new SqlConnection("server=.;uid=sa;pwd=1;database=dPnY;");
SqlCommand cmd1
= new SqlCommand();
SqlCommand cmd2
= new SqlCommand();
cmd1.Connection
= Connection;
cmd2.Connection
= Connection;
Connection.Open();
SqlTransaction sqlTran
= Connection.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
//SqlCommand cmd1 = Connection.CreateCommand();
//SqlCommand cmd2 = Connection.CreateCommand();


try
{
cmd1.CommandText
= "insert into tBom (cMemo) Values('a')";
cmd1.Transaction
= sqlTran;
cmd1.ExecuteNonQuery();
sqlTran.Commit();
//下面一句故意让其出错,让事务不能提交
int i = Convert.ToInt32("a");

cmd2.CommandText
= "insert into tBom (cMemo) Values('b')";
cmd2.Transaction
= sqlTran;
cmd2.ExecuteNonQuery();

sqlTran.Commit();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
sqlTran.Rollback();

}
finally
{
Connection.Close();
sqlTran.Dispose();
}

  问题是:代码肯定没错,我在做一个很大的项目,所以要考虑很多并发性问题,组长说一定不能用分布式,上面的代码是我写的一段模拟代码,故意让事务卡主不能提交,我在执行上面代码时,在去数据库查询分析器查询,发现表被锁住了,System.Data.IsolationLevel.ReadUncommitted这个我已经让他可以读脏数据了,还是不行,回答好的话可以再加分的。。

问题补充: 比如说我有两个操作员都对局域网上的服务器是数据库进行如下操作,上面的代码是每个操作员要执行的代码,实际中SQL语句比上面的要复杂得多,带很多存储过程,所以出问题的可能性很大,我故意让上面的模拟过程在中间卡住,但是我想要其他用户在卡住的事务提交前仍然可以读到数据或者操作数据库,所以就在设置事务为ReadUncommitted,可读脏数据,可是依然不行,就是这个问题了 不好意思各位上面代码第一个提交sqlTran.Commit();我本来是注释掉了,提问贴代码时不小心忘记注释了,大家注释掉就能发现问题饿了
308009625的主页 308009625 | 初学一级 | 园豆:150
提问于:2010-08-19 11:39
< >
分享
所有回答(5)
0

根据你补充的, 修改了程序:

  SqlConnection Connection = new

  SqlConnection("server=YKZSHUAI-PC\\SQL2010;uid=sa;pwd=sa;database=dPnY;");
            SqlCommand cmd1 = new SqlCommand();
            SqlCommand cmd2 = new SqlCommand();
            cmd1.Connection = Connection;
            cmd2.Connection = Connection;
            Connection.Open();
            SqlTransaction sqlTran = Connection.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
         
            try
            {
                cmd1.CommandText = "insert into tBom (cMemo) Values(12)";
                cmd1.Transaction = sqlTran;
                cmd1.ExecuteNonQuery();
                //sqlTran.Commit();

                //读取脏数据
                cmd2.CommandText = "select * from  tBom";
                cmd2.Transaction = sqlTran;
                DataTable dt = new DataTable();
                SqlDataAdapter da = new SqlDataAdapter(cmd2);
                da.Fill(dt);
               
                //我把 cMemo 列改成 int,所以下面SQL语句会出错,事务不能提交。

      cmd2.CommandText = "insert into tBom (cMemo) Values('f')";
                cmd2.Transaction = sqlTran;

                cmd2.ExecuteNonQuery();

                sqlTran.Commit();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                sqlTran.Rollback();
            }
            finally
            {
                Connection.Close();
                sqlTran.Dispose();
            }

            Console.Read();
          

中间读取的脏数据(刚刚插入的数据):

 

结论就是:你的程序可以读取脏数据,只是必须在程序中来读取、不能用查询分析器来读取、因为并未真正提交到数据库。

脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务刚好访问到了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,

HUHU慈悲 | 园豆:9973 (大侠五级) | 2010-08-19 12:10
不好意思,误导你了,前面的那次提交我本来是注释掉的,刚提问题的时候忘了注释了
支持(0) 反对(0) 308009625 | 园豆:150 (初学一级) | 2010-08-19 15:02
按照你补充的说明,我修改了程序(如上),做了下测试、我在程序中尝试读取脏数据,没问题的, 可以读(如上图),但是不能在数据库查询分析器里面读取、因为那里面只能读取提交后的数据、在事务中处理的数据都只是逻辑写入,并不是物理写入,也就是说没有写入磁盘。
支持(0) 反对(0) HUHU慈悲 | 园豆:9973 (大侠五级) | 2010-08-21 13:14
0

sqlTran.Commit();
  //下面一句故意让其出错,让事务不能提交
  int i = Convert.ToInt32("a");

你故意出错的上面一句,已经提交事务了。

Launcher | 园豆:45050 (高人七级) | 2010-08-19 13:02
0

楼主我有两个疑问。

1.为啥你同一个事务,第二个语句就没有执行,第一个insert后就马上commit了?那还怎么rollback?

2.如果是要读脏数据,select 后加with(nolock)这样行得通不?

xgdw | 园豆:4 (初学一级) | 2010-08-19 15:01
不好意识,第一个提交我忘记注释了,读脏数据肯定不行,要能读到数据库在事务开始前的数据
支持(0) 反对(0) 308009625 | 园豆:150 (初学一级) | 2010-08-19 15:05
1
  sqlTran.Commit(); //这一句不应该有,应该放到最后。因为已经提交了。下面的错误怎么回滚上面已提交的操作呢?
//下面一句故意让其出错,让事务不能提交
int i = Convert.ToInt32("a");
慧☆星 | 园豆:5722 (大侠五级) | 2010-09-03 08:52
0




TransactionOptions option
= new TransactionOptions();
option.IsolationLevel
=System.Transactions.IsolationLevel.ReadCommitted;
using (TransactionScope scope=new TransactionScope(TransactionScopeOption.Required,option))
{


//提交事务处理
scope.Complete();
}
我用这个。
中尉 | 园豆:252 (菜鸟二级) | 2010-09-03 09:13
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册