现在用C#做一个程序,
程序有3步,
第一步,从数据库中读取数据
第二步,修改数据,由于修改计算比较复杂,存储过程不能完成,所以是用C#来完成的。
第三步,将数据写回数据库这这里面有个问题,就是多个用户同时修改数据时,容易混乱。
现在我的做法是,在表上增加一个字段Lock,每次读取数据前,判断Lock是否为0,如果是,设置为1,然后读取数据,交给C#计算,最后把计算结果写回数据库,再把Lock字段设置为0但我总觉得这种方法太苯了,请问各位前辈,MSSQL有提供这样类似的功能吗?如果有,该如何实施?先谢谢大家

解决方案 »

  1.   


    1 如何锁一个表的某一行
    /*
            测试环境:windows 2K server + Mssql 2000
            所有功能都进行测试过,并有相应的结果集,如果有什么疑义在论坛跟帖
            关于版权的说明:部分资料来自互联网,如有不当请联系版主,版主会在第一时间处理。
            功能:sql遍历文件夹下的文本文件名,当然你修改部分代码后可以完成各种文件的列表。
    */
    A 连接中执行SET TRANSACTION ISOLATION LEVEL REPEATABLE READbegin transelect * from tablename with (rowlock) where id=3waitfor delay '00:00:05'commit tranB连接中如果执行update tablename set colname='10' where id=3 --则要等待5秒update tablename set colname='10' where id <>3 --可立即执行2 锁定数据库的一个表SELECT * FROM table WITH (HOLDLOCK)
    注意: 锁定数据库的一个表的区别SELECT * FROM table WITH (HOLDLOCK)
    其他事务可以读取表,但不能更新删除SELECT * FROM table WITH (TABLOCKX)
    其他事务不能读取表,更新和删除加with (rowlock)
      

  2.   

    回楼上
    现在计算的程序写了有1000多行了,不可能再用存储过程完成的。C#里的List<T>等对象,也不是存储过程可以取代的。
    难到没有办法了吗?
      

  3.   

    to:wzy_love_sly 
    第一步,从数据库中读取数据 --在此处加锁,SELECT完毕后,锁就自动释放了第二步,修改数据,由于修改计算比较复杂,存储过程不能完成,所以是用C#来完成的。 --上面锁释放了,可是这里的运算才刚刚开始,请注意,计算是在C#里,不在MSSQL中第三步,将数据写回数据库
      

  4.   

    用 事务+ 行锁 来实现,上面的 wzy_love_sly  已经说得很清楚了
      

  5.   

    to:wzy_love_sly 
    第一步,从数据库中读取数据 --在此处加锁,SELECT完毕后,锁就自动释放了 
    我想问问,第一步完成,事务是否已经结束了?
    ---\\\\
    NO
      

  6.   

    函数大概是这个样子的private void fun(){
       DataBase.Open()  //读出数据
      ArrayList tList=DataBase.read("SELECT LineA,LineB,LineC,LineD FROM Table")
      
      //这里是大量的计算
      for(int i=0;i<tList.Count;i++){
       //....
      }  //把数据写回去
      DataBase.Update("Update Table SET LineA=@LineA,LineB=@LineB,LineC=@LineC,LineD=@LineD",tList)
    }请问楼上,事务是在 SELECT时开始,在Update时结束吗?
      

  7.   

    这个是要控制在读数据时,就应该放置锁,目的是在于不让其实用户同时读此数据,而不是防止其它用户更新数据.
    我认为2楼方法不适用.这个必须在读数据时就加排它锁xlock,配置paglock,不能配置rowlock.像楼主12楼的写法,需要改成事务提交的方式,不知道楼主有没有这方面的基类可以调用.
      

  8.   

    begin tran
       select * from tb with(xlock,paglock) where id=3\
       --直到这个事务结束,也就是commit tran 或是rollback tran ,其它用户才能读取到id=3的这条记录.
    commit tranrowlock在mssql里,很难使用,因为行级锁对于sql server来讲,需要更高的代价来控制
    由于很多数据行存在于一个数据页内,锁数据页要比锁行代价低
    而且如果更新多条数据都存在于一个数据页,那么如果使用行级锁,极有可能会造成多个用户行锁定方向不同而产生锁死
    而锁页,这种情况就会减少.
      

  9.   


    嗯,只能改程序,配置连接事务SqlTransaction myTransaction = myConn.BeginTransaction();
      

  10.   

    要不就把逻辑搬到存储过程,用排它锁tablock锁全表,要不就加字段控制,没其他办法,行级的排它没有
      

  11.   


    使用paglock,页锁,这样只锁定数据行所在的一页,其它的数据页还可以读取.tablock就不好了.
      

  12.   


    呵呵,难道完美也用.net?加字段+事务解决吧,我感觉这个不错,
    而且查询和更新字段的时候注意加上排它锁,禁止
    其他连接读出数据,这样就能保证只有你一个人操作数据了
      

  13.   

    .net会一点,在公司都是封装好的东西,整天都是照着前人写的抄,所以.net感觉一点都不会.
      

  14.   

    谢谢楼上各位
    昨晚也去google了解一下,的确只有SqlTransaction myTransaction = myConn.BeginTransaction();才可解决问题
    事务对象有隔离方式的属性Chaos 无法改写隔离级别更高的事务中的挂起的更改。 
    ReadCommitted 在正在读取数据时保持共享锁,以避免脏读,但是在事务结束之前可以更改数据,从而导致不可重复的读取或幻像数据。 
    ReadUncommitted 可以进行脏读,意思是说,不发布共享锁,也不接受独占锁。 
    RepeatableRead 在查询中使用的所有数据上放置锁,以防止其他用户更新这些数据。防止不可重复的读取,但是仍可以有幻像行。 
    Serializable 在DataSet上放置范围锁,以防止在事务完成之前由其他用户更新行或向数据集中插入行。 
    Unspecified 正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。 象我这样的程序,用那种比较好呢?
      

  15.   

    同意"完美行动 "在16楼的说法。我理解的是在BeginTransaction()时,不用设置任何隔离方式;在SELECT 时,使用 pageLock在Update结束后,调用 Transaction.commit()结束事务,取消锁
      

  16.   


    就是这样子.select 时用with(xlock,paglock).
      

  17.   

    防止并发操作,可以在数据库中增加一个最后修改时间Upd_date的字段1、读取最后修改时间到变量 @t中2、 修改的时候加上条件where upd_date=@t,
    如果相等,就说明从读取到写入数据库,就没有别人修改过,可以修改,
    否则就不能修改,在写入的时候被别的用户修改过了,提示一个错误!
    update tt from col=,upd_date=getdate()
    where upd_date=@t
      

  18.   

    xlock表示“排他锁”
    pageLock表示“锁页”我想用TableLock是否更加安全?谢谢,结帖