目前在一个SQLServer的数据库项目中遇到一个表锁定问题,请教各位高人解答。
就是有一个表被后台程序定时地写,当正在写入数据时,前端用户程序无法查询该表的数据,总报错:超时已过期
因为这个表还涉及到一个子表的数据也在写入,因此整个代码写在一个事务中,目前怀疑是sql server 2008 将这个表进行了表一级锁定,有没有办法将其修改成 行锁?在 insert into语句上 支持指定行锁 操作呢 还是要将整个数据库修改成脏读(read_commited)?又担心一旦修改 导致数据库崩溃。都快急死了.   
 

解决方案 »

  1.   

    /*--处理死锁 查看当前进程,或死锁进程,并能自动杀掉死进程 因为是针对死的,所以如果有死锁进程,只能查看死锁进程
     当然,你可以通过参数控制,不管有没有死锁,都只查看死锁进程--邹建 2004.4--*//*--调用示例 exec p_lockinfo
    --*/
    create proc p_lockinfo
    @kill_lock_spid bit=1,  --是否杀掉死锁的进程,1 杀掉, 0 仅显示
    @show_spid_if_nolock bit=1 --如果没有死锁的进程,是否显示正常进程信息,1 显示,0 不显示
    as
    declare @count int,@s nvarchar(1000),@i int
    select id=identity(int,1,1),标志,
     进程ID=spid,线程ID=kpid,块进程ID=blocked,数据库ID=dbid,
     数据库名=db_name(dbid),用户ID=uid,用户名=loginame,累计CPU时间=cpu,
     登陆时间=login_time,打开事务数=open_tran, 进程状态=status,
     工作站名=hostname,应用程序名=program_name,工作站进程ID=hostprocess,
     域名=nt_domain,网卡地址=net_address
    into #t from(
     select 标志='死锁的进程',
      spid,kpid,a.blocked,dbid,uid,loginame,cpu,login_time,open_tran,
      status,hostname,program_name,hostprocess,nt_domain,net_address,
      s1=a.spid,s2=0
     from master..sysprocesses a join (
      select blocked from master..sysprocesses group by blocked
      )b on a.spid=b.blocked where a.blocked=0
     union all
     select '|_牺牲品_>',
      spid,kpid,blocked,dbid,uid,loginame,cpu,login_time,open_tran,
      status,hostname,program_name,hostprocess,nt_domain,net_address,
      s1=blocked,s2=1
     from master..sysprocesses a where blocked<>0
    )a order by s1,s2select @count=@@rowcount,@i=1if @count=0 and @show_spid_if_nolock=1
    begin
     insert #t
     select 标志='正常的进程',
      spid,kpid,blocked,dbid,db_name(dbid),uid,loginame,cpu,login_time,
      open_tran,status,hostname,program_name,hostprocess,nt_domain,net_address
     from master..sysprocesses
     set @count=@@rowcount
    endif @count>0
    begin
     create table #t1(id int identity(1,1),a nvarchar(30),b Int,EventInfo nvarchar(255))
     if @kill_lock_spid=1
     begin
      declare @spid varchar(10),@标志 varchar(10)
      while @i<=@count
      begin
       select @spid=进程ID,@标志=标志 from #t where id=@i
       insert #t1 exec('dbcc inputbuffer('+@spid+')')
       if @标志='死锁的进程' exec('kill '+@spid)
       set @i=@i+1
      end
     end
     else
      while @i<=@count
      begin
       select @s='dbcc inputbuffer('+cast(进程ID as varchar)+')' from #t where id=@i
       insert #t1 exec(@s)
       set @i=@i+1
      end
     select a.*,进程的SQL语句=b.EventInfo
     from #t a join #t1 b on a.id=b.id
    end
    go
      

  2.   

    多谢楼上的, 其实我的问题是,sql server2008应该支持并发地一个写一个读(同一张表)吧,目前我还没找到合适的测试方法,是不是在写时sql server的默认锁级别发生变化了?能不能将其固定?
    有没有好的解决办法,期望各位讨论下。
      

  3.   

    你在insert into上加锁?
    没有这样的吧。我觉得你应该从两个方面入手:
    1:你的程序定时写的代码入手,有没有加锁、加的什么锁?而且代码执行是不是很耗时?
    2:你前台查询语句写法是不是很耗时?如果你程序定时写的代码哪里有锁(如果是表锁,尽量改为行锁。当然具体看自己的业务),那你前台查询的时候可以加NOLOCK忽略锁。这样的话就可以达到脏读的概念。
      

  4.   


    多谢 madStone_l脏读目前来讲基本可接受,但真的不清楚为什么sql server2008会将写的锁升级?是真的吗?
    有没有专门研究这方面的?讨论充分后一起加分。
      

  5.   

    select语句中使用with(nolock)试试
      

  6.   

    查询的开始加上
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
      

  7.   


     在查询的开始加上
     SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 那还要改回去吧 想知道 sql server2008 的写锁 是不是存在自动从行锁 到表锁,希望大家多讨论下。
     
     
      

  8.   

    首先确定是表锁的问题吗???如果是更新引起别人不能查询的话,更新时可以加更新锁 UPDATE TB WITH(UPDLOCK)...
      

  9.   


     是这样的,一个执行时间有点长的写记录事务正在执行,结果客户端程序抓取该表记录时报告:超时
     那插入记录时是不是可以指定为 行锁
     insert into XXX (with rowlock) ...