有三个存储过程,p1:使表1的rno加1;p2:使表2的rid加1;p3:更新表3的num(库存数量)在VB里,首先启动事务,“exec p1 → insert into c_m”(步骤一),然后循环“exec p2 → insert into c_d → exec p3”(步骤二),循环结束后结束事务,如果中间有出错,则回滚事务。疑问1:只有一个用户在操作,在第2次执行步骤二的p3时出错,事务回滚:发现所有的insert into、p2和p3都有回滚,唯独没有回滚p1更新的rno,请问这是怎么回事?疑问2:假设有多个用户同时进行此操作,某个用户在第N次执行步骤二的p3时出错,请问这样的情况是怎么回滚的,是不是从启动事务开始就会锁定表1、表2、表3?疑问3:事务回滚是会回滚存储过程或函数里的所有操作?
谢谢!

解决方案 »

  1.   


    请问如何设置检查点,我是用SQL2000
      

  2.   

    可以帖出完整代码吗?
    vb的和sp的
      

  3.   


    CREATE PROCEDURE p1(@rno VARCHAR(10) OUTPUT)
    AS
    BEGIN
     SET NOCOUNT ON
     -- 表1的rno,VARCHAR,只有一行,值的格式ymmddxxxx(前5位年月日,后4位序号)
     DECLARE @a VARCHAR(10), @b VARCHAR(10
     SELECT @a=RIGHT(CONVERT(VARCHAR(6),GETDATE(),12),5)+'0001'
     SELECT @b=rno+1 FROM 表1
     IF @a>@b
      SELECT @rno=@a
     ELSE
      SELECT @rno=@b IF @b IS NULL
      INSERT INTO 表1(rno) VALUES (@rno)
     ELSE
      UPDATE 表1 SET rno=@rno SET NOCOUNT OFF
    END
    -------------------------------------------------------------CREATE PROCEDURE p2(@rid VARCHAR(10) OUTPUT)
    AS
    BEGIN
     SET NOCOUNT ON
     -- 表2的rid,CHAR,只有一行,值只记录序号 SELECT @rid=@rid+1 FROM 表2 IF @rid IS NULL
      INSERT INTO 表2(rid) VALUES (@rid)
     ELSE
      UPDATE 表2 SET rid=@rid SELECT @result=1 SET NOCOUNT OFF
    END
    -------------------------------------------------------------CREATE PROCEDURE p2(@sid VARCHAR(25), @sale_num NUMERIC(15,5), @result BIT=0 OUTPUT)
    AS
    BEGIN
     SET NOCOUNT ON
     -- 表3用于保存库存数量,sid:品种ID,num:库存数量
     IF NOT EXISTS (SELECT num FROM 表3 WHERE sid=@sid AND num>@sale_num)
      RETURN UPDATE 表3 SET num=num-@sale_num WHERE sid=@sid SET NOCOUNT OFF
    END' VB代码
    ' 表4 销售主表 表5 销售副表
    ' objcn as Connection,objcmd as Command On Error GoTo Err_Proc Dim strrno As String, strrid As String, i As Integer objcn.BeginTrans
     objcmd.CommandType = adCmdStoredProc
     objcmd.CommandText = "p1"
     objcmd.Execute strno=objcmd.Parameters("@rno") objcn.Execute "INSERT INTO 表4 (rno, ...) VALUES ('" & strno & "' ...)" For i=1 To VSFlexGrid1.Rows-1
      objcmd.CommandType = adCmdStoredProc
      objcmd.CommandText = "p2"
      objcmd.Execute
      
      strrid=objcmd.Parameters("@rno")  objcn.Execute "INSERT INTO 表5 (rno, rid, sid ...) VALUES ('" & strno & "' ...)"  objcmd.CommandType = adCmdStoredProc
      objcmd.CommandText = "p3"
      objcmd.Parameters("@sid")=VSFlexGrid1.TextMatrix(i, VSFlexGrid1.ColIndex("sid"))
      objcmd.Parameters("@sale_num")=VSFlexGrid1.TextMatrix(i, VSFlexGrid1.ColIndex("sale_num"))
      objcmd.Execute  If objcmd.Parameters("@result")=0 Then
       MsgBox "更新库存失败!"
       objcn.RollbackTrans
      End If
     Next objcn.CommitTrans
     MsgBox "单据已经保存!"
     Exit SubErr_Proc:
     objcn.RollbackTrans
      

  4.   

    在存储过程(a)调用存储过程(b)的时候..被调用的存储过程(b)不要写事务..
    写了事务就表示b已经完成.已经修改记录了..在a中出错.将不会回滚资料了.
      

  5.   

    晕死,CSDN不能修改帖子一个地方打错了:p2没有“SELECT @result=1”,这个应该在是在p3的set nocount off的前面
    因为现在手头没有代码,这些是现写的,大体就这样,请各位帮忙看一下。
    我现在比较不明白就是多次执行p3后,如果也有其他用户在进行类似操作,那这个库存数量是如何回滚的。
      

  6.   

    SQL Server 数据库引擎将忽略内部事务的提交。根据最外部事务结束时采取的操作,将提交或者回滚内部事务。如果提交外部事务,也将提交内部嵌套事务。如果回滚外部事务,也将回滚所有内部事务,不管是否单独提交过内部事务
    create table tb (id int)
    go
    create procedure outproc as
    begin
    begin transaction OutOfProc
    exec inproc
    rollback transaction OutOfProc
    end
    go
    create procedure inproc as
    begin
    begin transaction InOfProc
    insert into tb select 100
    commit transaction InOfProc
    select * from tb
    end
    go
    exec outproc
    go
    select * from tb
    drop table tb
    drop procedure outproc,inproc
    /*
    id
    -----------
    100(1 行受影响)id
    -----------(0 行受影响)
    */
      

  7.   

    To qianjin036a 对你说的我的理解是:SQL只会对最外层的事务进行处理,例如你给的例子,内嵌的inproc虽然提交事务,但最外层调用他的outproc回滚事务,所以inproc也跟着回滚了那像我在VB里回滚事务,那也就是说在事务开始到回滚过程中所有的操作(包括存储过程)都将会被回滚是这样吗?
      

  8.   

    SAVE TRANSACTION语句在事务内设置一个存储点,当事务执行到该存储点时,SQL Server存储所有被修改的数据到数据库中。ROLLBACK TRAN my_存储点名 可以回滚到“my_存储点名”这个存储点。
      

  9.   

    谢谢各位不过各位并没有回答我,像我那样执行,如果多用户同时执行,出错回滚会怎么样是从事务开始就锁定几个表,还是交替更新表,如果是交替的话,例如用户A将商品A的数量更新成10,商品B数量更改成0,而同时用户B也更新商品A的数量为9,这时用户A在更新商品C时出错,那商品A的数量是回滚成10还是9)
      

  10.   

    做了一个测试程序,界面只有一个复选框(复选框被勾选表示到最后回滚,否则提交)和一个按钮(点按钮开始执行)
    新建一表test,而有一列ca,值为0
    同时打开两个程序,A勾选复选框,结束时会回滚,B结束时提交,A先开始,当A弹出“暂停”对话框时B出现没有响应,点确定后发现ca的值是2
    这好像说明SQL会锁定更新的表直至事务提交或回滚--附事件探查器------------
    set implicit_transactions on 
    go
    UPDATE test SET ca=ca+1 --回滚
    go
    set implicit_transactions on 
    go
    UPDATE test SET ca=ca+1 --回滚
    go
    UPDATE test SET ca=ca+1 --提交
    go
    UPDATE test SET ca=ca+1 --提交
    go
    IF @@TRANCOUNT > 0 COMMIT TRAN
    go
    IF @@TRANCOUNT > 0 ROLLBACK TRAN  为什么A回滚是在B的提交之后呢??而且值还是2
    go
    ----------------------------------
        Dim objConn As Connection
        
        Set objConn = New Connection
        objConn.ConnectionString = "Provider=SQLOLEDB.1;Password=;Persist Security Info=True;User ID=sa;Initial Catalog=test;Data Source=(local)"
        objConn.Open
        
        objConn.BeginTrans
        If CBool(Check1.Value) Then
            objConn.Execute "UPDATE test SET ca=ca+1 --回滚"
            MsgBox "暂停"
            objConn.Execute "UPDATE test SET ca=ca+1 --回滚"
            
            objConn.RollbackTrans
            objConn.Close
            
            MsgBox "回滚"
        Else
            objConn.Execute "UPDATE test SET ca=ca+1 --提交"
            objConn.Execute "UPDATE test SET ca=ca+1 --提交"
            
            objConn.CommitTrans
            objConn.Close        MsgBox "完成"
        End If
      

  11.   

    为什么A回滚是在B的提交之后呢??而且值还是2 >>>>当A出现"暂停"时,B已经启动,并且等待A的独占锁釋放.当A点"确定"时,A独占锁釋放,B得以往下运行,锁定test表A只能等待B运行结束後才继续执行下去。
      

  12.   

    表上的独占锁是指同一时间只能有一个session持有.
      

  13.   

    这个我明白,只是我不太明白的是,像上面那样循环执行存储过程和Insert into,那表会被锁定吗?如果没有被锁定,那如果出错回滚会出现什么情况?谢谢