参考t-sql帮助,搜索关于数据加锁,隔离级别
仔细看看,会有很大帮助的
:)

解决方案 »

  1.   

    SQL Server 的锁机制已经涉及的很好了,如果你的系统对数据完整性、数据一致性要求的非常严格,才需要考虑人工处理锁的问题。
      

  2.   

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    BEGIN TRANSACTION
       SELECT *FROM table WITH (UPDLOCK)   ...COMMIT TRANSACTION
      

  3.   

    1.在更新數據時,希望記錄鎖定,即當用戶決定修改時,即對用戶當前
    記錄施加記錄鎖,在更新完成後解鎖,該如何實現?sql數據庫自身提供的行級鎖,就能很好的這個問題。通常沒有必要自己在添加鎖。
      

  4.   

    nielisheng(阿土),
      你好,
      你的意思是先設置隔離層別,再用事務處理,
    但這只能解決更新時加鎖的問題,如果其它交
    易再試圖加鎖呢,該如何處理,如題,還有新加
    記錄時呢?
      謝謝
      

  5.   

    cqcjoe(早已女亂馬),
      你好,
      但它的行鎖只在更新的那剎那才會加啊,
    我希望在用戶准備更新,即修改資料時就應
    鎖住該記錄,不允許其它用戶修改,避免Dirty
    Read
      謝謝
      

  6.   

    1.在应用程序里面做一个加锁解锁的程序,首先在数据库记录表加一个锁字段,0表示未锁,1表示锁上了。然后加锁解锁做成公共的函数或者method,在你的程序打开编辑一条记录的界面时候(我这就认为你有编辑的企图,这个词大概用的不好,呵呵),就加锁这条记录。这时候,别人不能编辑这条记录或者甚至不能打开查看他(up 2 u),编辑成功后,关闭窗口时解锁
    2.上面的做好了,这个问题就是一样的了
    3.可以让id自动生成,按照你的法则。插入数据必须用transaction. 因为插入数据库是很短时间的事情,瞬间,只需要锁住数据库零点几秒。而且保证他的不重复。几乎不大可能在这零点几秒的同时有两个用户进行插入。 假使真的同时发生了,那么transaction会失败。如果在应用程序里面算,那就不行了,因为你需要把表锁住几分钟甚至十几分钟甚至更长ps: 对于大型的用户数很多的系统,比如证券交易系统,第3点可能不对,请高手来说几句。
      

  7.   

    2
     sp_lock, sp_who
    3
     identity(1,1)
      

  8.   

    KnowLittle(人傻不要紧,只要肯学习。),
      又看到你了,你好,
      我也在這樣考慮,現在我最大的缺點在於對那個該死的
    SQLServer不熟,還有希望能同高手探討看有無多樣方法的
    可能性,呵~(這可不是貪心~),我在規劃一個工程,碰上這
    些麻煩(可能還很多),先來這征求大家的意見
      謝謝你了,你的數據庫好了麼?
      

  9.   

    其他的可以用共享锁,只读,因为你要在用户读数据时(不阻塞其它事务),用个
    if (had locked) then 
      SELECT *FROM table WITH (HOLDLOCK)
    else
      SELECT *FROM table WITH (UPDLOCK)
    end if两个用户同时不能修改同一条,几条记录,你不是此意吗?
      

  10.   

    nielisheng(阿土),
      你好,
      identity(1,1)在第3個中並不適用,原因在於
    該主鍵值(須值唯一)由用戶維護的,你再試想想
      

  11.   

    其实不是所有问题都要放到sqlserver内部解决,要内外结合。:)
    不过对于第三点,超大型系统的经验我真的缺乏,不然可以给你更多有价值意见
    没有 :(
      

  12.   

    nielisheng(阿土),
      你好,
      <两个用户同时不能修改同一条,几条记录,你不是此意吗?>
      是,正是此意,你的意思是這樣可以判定此記錄有無被其它用戶
    鎖住嗎,在SQLServer中是這樣用嗎,謝謝
      

  13.   

    KnowLittle(人傻不要紧,只要肯学习。),
      你好,
      人無完人,不管怎麼樣,我都很感謝你
      

  14.   

    nielisheng(阿土),
      你好,
      <何谓用戶維護?>
      我這的意思是說該主鍵值(如合同編號等)內容可由用戶自己
    決定填寫
      

  15.   

    1 主鍵值,改成identity(1,1)  推荐;
    2 给录入人员的录入数据分段;
    3 如重复,则加1,如为字符aab002会dididkd等则只能提示用户;
      

  16.   

    并发问题
    如果没有锁定且多个用户同时访问一个数据库,则当他们的事务同时使用相同的数据时可能会发生问题。并发问题包括: 丢失或覆盖更新。
    未确认的相关性(脏读)。
    不一致的分析(非重复读)。
    幻像读。 
    丢失更新
    当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。例如,两个编辑人员制作了同一文档的电子复本。每个编辑人员独立地更改其复本,然后保存更改后的复本,这样就覆盖了原始文档。最后保存其更改复本的编辑人员覆盖了第一个编辑人员所做的更改。如果在第一个编辑人员完成之后第二个编辑人员才能进行更改,则可以避免该问题。未确认的相关性(脏读)
    当第二个事务选择其它事务正在更新的行时,会发生未确认的相关性问题。第二个事务正在读取的数据还没有确认并且可能由更新此行的事务所更改。例如,一个编辑人员正在更改电子文档。在更改过程中,另一个编辑人员复制了该文档(该复本包含到目前为止所做的全部更改)并将其分发给预期的用户。此后,第一个编辑人员认为目前所做的更改是错误的,于是删除了所做的编辑并保存了文档。分发给用户的文档包含不再存在的编辑内容,并且这些编辑内容应认为从未存在过。如果在第一个编辑人员确定最终更改前任何人都不能读取更改的文档,则可以避免该问题。不一致的分析(非重复读)
    当第二个事务多次访问同一行而且每次读取不同的数据时,会发生不一致的分析问题。不一致的分析与未确认的相关性类似,因为其它事务也是正在更改第二个事务正在读取的数据。然而,在不一致的分析中,第二个事务读取的数据是由已进行了更改的事务提交的。而且,不一致的分析涉及多次(两次或更多)读取同一行,而且每次信息都由其它事务更改;因而该行被非重复读取。例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果只有在作者全部完成编写后编辑人员才可以读取文档,则可以避免该问题。幻像读
    当对某行执行插入或删除操作,而该行属于某个事务正在读取的行的范围时,会发生幻像读问题。事务第一次读的行范围显示出其中一行已不复存在于第二次读或后续读中,因为该行已被其它事务删除。同样,由于其它事务的插入操作,事务的第二次或后续读显示有一行已不存在于原始读中。例如,一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主复本时,发现作者已将未编辑的新材料添加到该文档中。如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。
    隔离级别
    当锁定用作并发控制机制时,它可以解决并发问题。这使所有事务得以在彼此完全隔离的环境中运行,但是任何时候都可以有多个正在运行的事务。可串行性是通过运行一组并发事务达到的数据库状态,等同于这组事务按某种顺序连续执行时所达到的数据库状态。 SQL-92 隔离级别
    尽管可串行性对于事务确保数据库中的数据在所有时间内的正确性相当重要,然而许多事务并不总是要求完全的隔离。例如,多个作者工作于同一本书的不同章节。新章节可以在任意时候提交到项目中。但是,对于已经编辑过的章节,没有编辑人员的批准,作者不能对此章节进行任何更改。这样,尽管有未编辑的新章节,但编辑人员仍可以确保在任意时间该书籍项目的正确性。编辑人员可以查看以前编辑的章节以及最近提交的章节。事务准备接受不一致数据的级别称为隔离级别。隔离级别是一个事务必须与其它事务进行隔离的程度。较低的隔离级别可以增加并发,但代价是降低数据的正确性。相反,较高的隔离级别可以确保数据的正确性,但可能对并发产生负面影响。应用程序要求的隔离级别确定了 SQL Server 使用的锁定行为。SQL-92 定义了下列四种隔离级别,SQL Server 支持所有这些隔离级别: 未提交读(事务隔离的最低级别,仅可保证不读取物理损坏的数据)。
    提交读(SQL Server 默认级别)。
    可重复读。
    可串行读(事务隔离的最高级别,事务之间完全隔离)。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    如果事务在可串行读隔离级别上运行,则可以保证任何并发重叠事务均是串行的。
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~下面四种隔离级别允许不同类型的行为。隔离级别 脏读 不可重复读取 幻像 
    未提交读 是 是 是 
    提交读 否 是 是 
    可重复读 否 否 是 
    可串行读 否 否 否 
    事务必须运行于可重复读或更高的隔离级别以防止丢失更新。~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    当两个事务检索相同的行,然后基于原检索的值对行进行更新时,会发生丢失更新。如果两个事务使用一个 UPDATE 语句更新行,并且不基于以前检索的值进行更新,则在默认的提交读隔离级别不会发生丢失更新。
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~``
    仔细看了手册,总结出对于第三点,只要把transaction isolation level设置程serializable应该就可以了
    请高手指正!因为在下又看到一段让我困惑的话
    SERIALIZABLE在数据集上放置一个范围锁,以防止其他用户在事务完成之前更新数据集或将行插入数据集内。这是四个隔离级别中限制最大的级别。因为并发级别较低,所以应只在必要时才使用该选项。该选项的作用与在事务内所有 SELECT 语句中的所有表上设置 HOLDLOCK 相同。
      

  17.   

    nielisheng(阿土),
      你好,
      <1 主鍵值,改成identity(1,1)  推荐;>
      <2 给录入人员的录入数据分段;>
      <3 如重复,则加1,如为字符aab002会dididkd等则只能提示用户;>
      1.不太適合,你可看一下我昨天發的貼子,其實是一體的(現在在已解決
    欄中,題目是[],奇怪,找不到了,copy在下面吧)********************************
    主键难题:有一order表,字段如下:
    order_id Char (12) 订购编号[定义为主键]
    cust_id Char (05) 客户编号
    order_date Datetime 订购时间
    ...假如上月(2002.12)客户(编号:WX005)有5个订单,本月已有
    2个订单,则数据如下:
    [订购编号] [客户号] [订购日期]
    WX0050212001 WX005 2002.12.01
    WX0050212001 WX005 2002.12.11
    WX0050212003 WX005 2002.12.15
    WX0050212004 WX005 2002.12.21
    WX0050212005 WX005 2002.12.28
    WX0050301001 WX005 2003.01.03
    WX0050301002 WX005 2003.01.05可以看出,order_id由下列规则自动生成:
    订单编号(12位)=客户编号(5位)+订购日期(4位)+自动递增流水号(3位)问题: 在SQL Server中应怎样处理才能使[订购编号]按此规则自动生成,
    难点在于它的流水号须随不同客户依次递增,且每月各客户的初始订购流
    水号须初始为001,然后再递增.请高手救急!高分相送,我有XXXX可用分可用!!!
    ********************************
      2.和3.
      

  18.   

    KnowLittle(人傻不要紧,只要肯学习。),
      你好,
      對,問題完全描述清楚,但具體解決呢,我頭好大...
      

  19.   

    你试一下巴
    transaction isolation level设置程serializable
    然后弄2个事务,第一个让他执行一段事件,未结束执行第二个,2个事务更新同一个表,并且基于以前检索的值进行更新,看看是否可以串行。
      

  20.   

    KnowLittle(人傻不要紧,只要肯学习。),
      你好,
      SQLServer中若有㊣確設置事務鎖,我相信它會執行的很好
    ,在交易1鎖住後可阻止交易2試圖的更新,
      但在增加記錄時呢,還可這樣處理嗎,好像不可以,應該是鎖
    整個表吧,因要阻止其它用戶同時增加,這樣是不是可行呢,還
    有,是不是還有其它方法呢?
      

  21.   

    建个xlh(系列号)表辅助处理,订购编号的规则好写,你在想一向,lx(类型 varchar),  val(当前最大值 varchar)
    DDBH(订单编号)      006
    THDBH(退货单编号)   007每次处理此表
      

  22.   

    nielisheng(阿土),
      你好,
      我覺得咱倆想一塊了,我有此意,但有出入,我的想法是:
      建立一加鎖控制表(如tbControl)
      table_name    char
      字段 table_name 裡放置所有需特別處理主鍵值的表名,
    如:
      table_name1
      table_name2
      table_name3
      ...  好,這樣處理後,在程序中這樣控制,當用戶試圖增加新
    記錄時,在更新的瞬間之前,在tbControl表中找到要更新
    的表名,給它施加鎖,在鎖成功後(如鎖不成功, 則表示有
    其它交易鎖住此表增加記錄), 尋找符合條件記錄的最大
    號,取其最大號加1,再和其它字段一起提交事務, 我考慮
    這適合系統自維護(根據一定規則)流水號的情況,不知這
    個方式是否可行,請批評指正  那麼在這個過程中,tbControl表實際上起一個鎖整個表
    的替代方法,避免真去鎖整個表,也好控制
      
      很想聽聽高手的意見,並給出實現方案,給高分,決不食言
      

  23.   

    合理安排表访问顺序
    在事务中尽量避免用户干预,尽量使一个事务处理的任务少些
    数据访问时域离散法
    数据存储空间离散法
    使用尽可能低的隔离性级别
    最后一点:尽量不要手工加锁,而采用SQL Server自身的锁机制。
      

  24.   

    但在增加記錄時呢,還可這樣處理嗎,好像不可以,應該是鎖
    整個表吧,因要阻止其它用戶同時增加,這樣是不是可行呢,還
    有,是不是還有其它方法呢?
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~`为什么要锁整个表?
    只要插入瞬间保证生成的ORDERID是唯一并且正确就可以了阿,事务会保证读了数据后被锁住,直到插入完成释放(isolationlevel 提交读  SQL Server 默认级别)
      

  25.   

    KnowLittle,nielisheng,
      你們好,
      用表級鎖的目的在於我要取符合一定規則記錄的最大號啊,
    如不如此,雖在更新時可控制唯一性,但我想在寫表時就已控
    制到記錄唯一,而減少中斷用戶操作,提示記錄重復
      在取最大號時,只能讓取號過程中的表一直處於一個用戶
    控制,才行啊,否則,就算取得最大號,但在未寫入表時,說不
    定有其它用戶提交成功,則此取號過程從技術上來說就已經
    失敗了,請仔細想想看,
      謝謝
      

  26.   

    KnowLittle,nielisheng,
      你們好,
      如上,我這樣作的目的就在於保證取最大號的過程,使它
    確實是取到符合一定規則的最大號,你們說是嗎
      是不是SQLServer中可不用這樣處理呢?
      

  27.   

    sql server 中用
    identity,很方便的,不过这里不适合你,你的订单号不同。写程序不是复杂,其实你的问题不必太复杂,
      

  28.   

    最大的为什么要表级锁?
    我在你前一个帖子里面不是写了怎么获得orderid吗?在那一瞬间就会判断出当前最大的. 不过这个id号在界面上是不可见的, 只有新增成功之后再调出来才可见.
    如果你要他在新增界面上就可见,那么的确是要表级锁, 但是这样代价太大了. 天知道一个用户输入一个合同要几分钟? 而且这个长长的orderid没必要让用户上来就可以看到阿.如果你一定可见,那么你可以这样, 
    确认前面有一个生成合同号的步骤(让他看一下),在生成之后, 即使用户不确认, 几秒钟内就会自动提交数据, 除非用户cancel.
    这几秒钟之内,把整个表锁了,这样才稍微可行一些
      

  29.   

    KnowLittle(人傻不要紧,只要肯学习。),
      你好,不好意思
      我想看還有沒有好的方法,這對我而言,多一個方法就多有一個
    選擇,呵~  <但是这样代价太大了. 天知道一个用户输入一个合同要几分
    钟? 而且这个长长的orderid没必要让用户上来就可以看到阿>
      其實,我的生成orderid的方法亦只是在最後提交的時候才生成
    ,update 和 insert 應分開考慮,update 應在用戶開始修正時即
    開始事務處理,而 insert 則在提交時開始事務即可,你在通看一
    下全文,一個實現模式不是隱約可現了麼~呵呵
      但我還不滿足啊,人傻不要紧,只要肯学习就好,我也相信這句
    話,呵~謝謝~
      

  30.   

    KnowLittle(人傻不要紧,只要肯学习。),
      你好,
      針對你最後的回復,還有一點要澄清,如你所說,
      /// 我在你前一个帖子里面不是写了怎么获得
      /// orderid吗?在那一瞬间就会判断出当前最
      /// 大的. 不过这个id号在界面上是不可见的,
      /// 只有新增成功之后再调出来才可见.
      但你有沒有想過,在tbControl中我只能登記每
    一個表唯一的表名,亦就是說,按你的意思,我只能
    登記此表的一個最大號,但如合同表中此最大號是
    根據客戶,日期來的啊,也就是說,在合同表中每一
    個客戶,每一個月都有它的最大號,要不然按你的
    說法,只能針對合同號表(注意,這裡才一個表)都
    要根據每一個客戶每個月(有在某個月補單的可能
    )登記它的最大號,亦就是說凡在我需類似處理的
    表為存儲它的最大號,都得另外單獨准備一個專門
    存儲最大號的表,這樣不是很麻煩嗎,
      

  31.   

    建议使用sql事务处理!
    1、
    begin tran 
      update ... where id=@id
    commit tran
    在sql中如果并发上面的代码应该是排队执行的!如果你在代码中修改了id值,那后一个用户,将修改失败,你可以通过@@ROWCOUNT来检查是否更新了行!
    2、
    你可以写回滚代码呀!
      begin tran
        update...
        if @@error<>0 then
          rollback tran
      commit tran
    3、你可以用自动增长的呀!如果你的id列须为如:a2001010212这样的有逻辑规则的记录的话
    create proce 名
    @列值 varchar(10),
    @编号 char(10) output
    begin tran
      set @编号=........
      insert 表 values (@编号,@列值)
    commit tran再在前端得到输出值
      

  32.   

    pengdali,
        你好,谢谢建议
        1.如果我用断开连接方式,如用户取一条记录,从它准备修改
    开始,是不是一直要保持数据库连接啊?
        2.同上
        3.谢谢,但还看得不是太明白
      

  33.   

    1、2、哦!你是说“无状态”与“有状态”呀!当然我建议“无状态”了!
      你不要保持数据库连接,直接update,如果你的id不允许修改,那后面的回覆盖前面的人修改的,如果id允许修改,那有可能后面的修改失败(如:你用时间戳当主键)
    另:在分布式系统中,大多数应用都是“无状态”,但你是小应用,就无所谓了!
    3、
    如:
      begin tran
        set @编号='A'+convert(char(8),getdate(),112)+(select max(id)+1 from 表)
        insert 编号,.. values (@编号...)
      commit tran应为在sql中并发情况下,sql会按一定规则,排队执行上面的代码!
      

  34.   

    pengdali,
        你好,
        1,2 我想采用"无状态",但怎样避免这种 dirty read 呢?
        3. 不错!这样可解决我的一大问题!
      

  35.   

    1、2
    哦!你的应用是以“读,改,写”来做的呀!
    那你可以加入一个时间戳字段,来标志是否被修改!
    如:
    declare @aa table (a int,b timestamp)
    insert @aa values(1)
    insert @aa values(2)
    insert @aa values(3)
    ---------******----------
    declare @temp1 int,@temp2 int
    select @temp1=a,@temp2=cast(b as int) from 表 where a=1 ---------例如:你这时在读取update @aa set a=8 where a=1 --------------这时有另一个人修改了记录update @aa set a=9 where a=@temp1 and cast(b as int)=@temp2
    -------按你预期是回修改的,但这时已经有人改了记录,时间戳改变了,所以将不会修改记录
    if @@ROWCOUNT<1
      print '修改失败!可能已经有人改变了记录'
    else
      print '修改成功!'
    -----这时用@@ROWCOUNT得到的是等于0的,应为没有影响任何行!
    -------*****----------
    上面说明了如何判断一条记录是否被人修该过了!
      

  36.   

    你在做应用时,不能在“读,改,写”的读时就锁定记录!应为你不能确定用户是否真的需要修改这条记录,用户的电脑死机,停电....情况!
    你的应用只能在确定更新时来判断是否已经有人改过记录了,而当前用户不知道!
    上面只是一个简单的思路!你可以继续向下做!如:
    if @@ROWCOUNT<1
      set @message='1' --将@message做为一个输出参数,返回给前台应用
    else
      set @message='0'
    ----------再在前台应用判断@message是否为1,为1的话读取现在的被别人修改后的值,并提示用户是否继续修改....
      

  37.   

    pengdali,
        你好,
        明白了你的意思,但這個實現我實在讀不明白,麻煩你再描述下
        謝!
      

  38.   

    declare @aa table (a int,b timestamp) -----建立表变量,就是模仿你的表
    insert @aa values(1)                 ----插入原始记录
    insert @aa values(2)
    insert @aa values(3)
    ---------******----------
    declare @temp1 int,@temp2 int     ----定义局部变量,模仿你的前台控件读取数据记录select @temp1=a,@temp2=cast(b as int) from 表 where a=1 ----模仿你这时在读取update @aa set a=8 where a=1 ----------模仿这时有另一个人修改了你刚刚读取的记录update @aa set a=9 where a=@temp1 and cast(b as int)=@temp2
    ------这时按你预期是回修改的,但这时已经有人改了记录,时间戳改变了,所以将不会修改记录if @@ROWCOUNT<1         ------@@rowcount是存储上条语句影响的行数
      print '修改失败!可能已经有人改变了记录'    --如果影响行数为0,也就是没有修改任何记录就报错
    else        -------修改成功的话,也就是影响了多条记录,就报对!
      print '修改成功!'------这些代码你可以马上在查询分析器里执行!
      

  39.   

    pengdali,
        你好,
        <不能在“读,改,写”的读时就锁定记录!>我沒打算這樣作,
    我的處理是,用戶按下EDIT後,鎖(或相當於鎖,作個標志什麼的等等)
    住記錄,連接斷開,在 update 時,先再檢查標志是否動過,再決定更新
    否,其實在我作這個標記後,我就不想讓其他用戶再有可能EDIT了
        我想你的意思也是這樣,但有這樣的問題:
        1.在SQLSERVER中的實現(麻煩老大再描述一下)
        2.如果交易1在打上標志後(update前)电脑死机,停电....,這個
    標志又該如何恢復呢?
        期待回復中...
      

  40.   

    pengdali,
        你好,
        我明白你的意思了,其實你要明白,在用戶A決定Edit(不是update)時,
    我就不允許其它用戶再能EDIT,你的方法只能保證資料正確性,還有造成
    用戶作業資源浪費(呵呵~),因其它用戶還是可以在你Edit時(未update前),
    update他的修改,我說的對不對...