问题描述
数据库SqlServer2008,创建一个存储过程createproceduresp_test1(@idint)asbegintransactionif@id=1beginrollbacktransactionendelsebegincommittransactionend
//调试代码publicboolTestProc(intid){try{//SqlCommandcmd=newSqlCommand("sp_test1");//cmd.CommandType=CommandType.StoredProcedure;SqlCommandcmd=newSqlCommand("execsp_test1@id");cmd.CommandType=CommandType.Text;cmd.Parameters.Add("@id",id);introwCount=SqlUtil.ExecuteNonQuery(cmd);returnrowCount>0;}catch(Exceptione){Console.WriteLine(e);}returnfalse;}
无论是使用CommandType.StoredProcedure还是CommandType.Text;只要当传入的参数是1时,都会抛出异常,也就是只要存储过程中执行到rollback时,就会抛出异常(我就是实际调用一个比较复杂的储存过程,然后一直抛出异常,在存储过程中增加了无数print语句跟踪,才觉得是这个rollback问题,创建这个存储过程测试的)当然,直接使用SqlServerManagementStudio执行execErpCore_Server.dbo.sp_test11,是成功执行的,并且没有异常信息异常信息EXECUTE后的事务计数指示BEGIN和COMMIT语句的数目不匹配。上一计数=1,当前计数=0。不知道有人碰到过这种情况没有?网上搜了一堆,基本没有看到有人提到过这个情况的
解决方案
本帖最后由 jestymat 于 2016-05-25 18:11:32 编辑
解决方案二:
begintran跟“committrans”/“rolltans”的个数不匹配。恐怕你的“无数print语句跟踪”也是很不准确、有一个漏网的吧?你确定你写的那个简单的demo一定会产生异常吗?在sqlserver高版本上也产生异常吗?如果真的是这样,你可以把这个简单的测试拿给微软看,它们的sqlserver2008还真的有bug呢!不过话说回来了,你为什么要在存储过程中要使用commit、roolback呢?当sqlserver执行一条命令时,它默认地本身就启动了一个事务,并不需要你再写一个begintran语句。你的存储过程要回滚数据修改语句,应该写raiserror(...)命令。我估计你是不知道如何使用t-sql语句来正规地抛出异常,只知道“正常结束”存储过程的语句,所以才画蛇添足地写了好几个事务语句。
解决方案三:
引用1楼sp1234的回复:
begintran跟“committrans”/“rolltans”的个数不匹配。恐怕你的“无数print语句跟踪”也是很不准确、有一个漏网的吧?你确定你写的那个简单的demo一定会产生异常吗?在sqlserver高版本上也产生异常吗?如果真的是这样,你可以把这个简单的测试拿给微软看,它们的sqlserver2008还真的有bug呢!不过话说回来了,你为什么要在存储过程中要使用commit、roolback呢?当sqlserver执行一条命令时,它默认地本身就启动了一个事务,并不需要你再写一个begintran语句。你的存储过程要回滚数据修改语句,应该写raiserror(...)命令。我估计你是不知道如何使用t-sql语句来正规地抛出异常,只知道“正常结束”存储过程的语句,所以才画蛇添足地写了好几个事务语句。
我敢确定你有没有仔细看帖子首先,这个并不是sqlserver2008的错误,储存过程在sqlserver2008中执行是不会报错的,只是在使用.NET调用的时候才会抛出异常其次,写这么简单的一个事务例子就是方便测试,难道我需要拿出实际当中碰到的,近百行sql,修改近10张表的存储过程,并且给出所有的表结构,以及可以供大家测试的数据,让大家测试吗?
解决方案四:
找到原因了,是封装的SqlUtil原因,使用原生的单个命令方法就不会抛出异常using(SqlConnectionconn=newSqlConnection(s)){conn.Open();SqlCommandcmd=newSqlCommand("sp_test1");cmd.CommandType=CommandType.StoredProcedure;//SqlCommandcmd=newSqlCommand("execErpCore_Server.dbo.sp_test1@id");//cmd.CommandType=CommandType.Text;cmd.Parameters.Add("@id",id);cmd.Connection=conn;introwCount=cmd.ExecuteNonQuery();}
封装的SqlUtil默认开启了事务,并且执行后提交事务如果换成原生的方法,则是introwCount=0;using(SqlConnectionconn=newSqlConnection(s)){conn.Open();using(SqlTransactiontran=conn.BeginTransaction()){SqlCommandcmd=newSqlCommand("ErpCore_Server.dbo.sp_test1");cmd.CommandType=CommandType.StoredProcedure;cmd.Parameters.Add("@id",id);cmd.Connection=conn;cmd.Transaction=tran;rowCount=cmd.ExecuteNonQuery();//执行到此处的时候,有可能会抛出异常tran.Commit();}}returnrowCount>0;
那么新的问题来了,为什么当存储过程中,执行了rollbacktransaction时,就抛出异常,而当存储过程执行了committransaction时,这个语句就不会抛出异常
解决方案五:
//调试代码publicboolTestProc(intid){try{//SqlCommandcmd=newSqlCommand("sp_test1");//cmd.CommandType=CommandType.StoredProcedure;SqlCommandcmd=newwww.60400.comSqlCommand("execsp_test1@id");cmd.CommandType=CommandType.Text;cmd.Parameters.Add("@id",id);introwCount=SqlUtil.ExecuteNonQuery(cmd);returnrowCount>0;}catch(Exceptione){Console.WriteLine(e);}returnfalse;