您的位置:首页 > 其它

封锁并发事务

2011-04-28 00:52 295 查看
1:事务的状态:

2:编写事务的时候应该遵循的原则

、(1): 在事务处理期间不要求对用户输入:

(2): 浏览数据时,尽量不打开是事务

(3):在所有预备的数据分析之前,不启动事务

(4);必须进行修改时启动事务,执行完成修改操作语句后立即提交或回退:

3:并发控制:

多个用户同时对同一数据对象进行读写操作,这种现象称为并发操作,显然并发操作

可以充分利用系统资源,提高效率,但若对这种并发操作不加以控制,它可能会破坏数据的

一致性

4。并发的错误情形;

1:两个事务读写同一数据而出现数据的不一致性错误:

2:数据丢失更新问题:

3,脏读:

5:封锁技术:

封锁是事务并发控制的主要手段,其作用是在事务T对某一数据对象(例如表)等、

进行操作前,先向系统发出请求,对其加锁,加锁后事务T对该数据对象有一定的控制,在事务

T释放所加的锁之前,其他事务不能更新此数据对象:

对锁机制的研究要具备两个条件:
1.数据量大
2.多个用户同时并发
如果缺少这两个条件,数据库不容易产生死锁问题。研 究起来可能会事倍功半。如果这两个条件都有,但你还是按数据库缺省设置来处理数据,则会带来很多的问题,比如:
1)丢失更新
A,B两 个用户读同一数据并进行修改,其中一个用户的修改结果破坏了另一个修改的结果
2)脏读
A用户修改了数据时,B用户也在读该数据,但A 用户因为某些原因取消了对数据的修改,数据恢复原值,此时B得到的数据就与数据库内的数据产生了不一致
3)不可重复读
B用户读出该数 据并修改,同时,A用户也在读取数据,此时A用户再读取数据时发现前后两次的值不一致
SQL SERVER 作为多用户数据库系统,以事务为单位,使用锁来实现并发控制。SQLSERVER使用“锁”确保事务完整性和数据一致性。

(1)封锁类型:(查资料)

s锁: 共享性封锁:

X锁: 排它锁:

例子:

以下在sql server 2005中会会话设置了TRACSACTION ISOLATION LEVEEL.

对于事务开始后的每个sql语句,系统将所有共享琐一直保持,直到事务结束:

use teaching_mis

go

set transaction isolation level repeatable read;

go

begin transaction;

go

select * from course

go

select * from students

go

commit transaction:

(2)

封锁的相容性及说明:

T1/T2

x

s

-

x

N

N

Y

s

N

Y

Y

-

Y

Y

Y

x—排它锁;

s___共享锁:

_:无锁:

Y:表示相容

如果两个封锁是不相容的,则后提出的封锁的事务要等待 (查资料,等待的例子)

(3): 封锁粒度: (查资料)

SQL Server 2000 具有多粒度锁定,允许一个事务锁定不同类型的的资源。为了使锁定的成本减至最少,SQL Server 自动将资源锁定在适合任务的级别。锁定在较小的粒度(例如行)可以增加并发但需要较大的开销,因为如果锁定了许多行,则需要控制更多的锁。锁定在较大的粒度(例如表)就并发而言是相当昂贵的,因为锁定整个表限制了其它事务对表中任意部分进行访问,但要求的开销较低,因为需要维护的锁较少。SQL Server 可以锁定行、页、扩展盘区、表、库等资源。

资源 级别 描述
RID 行锁 表中的单个行
Key 行级锁 索引中的行
Page 页级锁 一个数据页或者索引页
Extent 页级锁 一组数据页或者索引页
Table 表级锁 整个表
Database 数据库级锁 整个数据库

选择多大的粒度,根据对数据的操作而定。如果是更新表中所有的行,则用表级锁;如果是更新表中的某一行,则用行级锁。
行级锁是一 种最优锁,因为行级锁不可能出现数据既被占用又没有使用的浪费现象。但是,如果用户事务中频繁对某个表中的多条记录操作,将导致对该表的许多记录行都加上了行级锁,数据库系统中锁的数目会急剧增加,这样就加重了系统负荷,影响系统性能。因此,在SQL Server中,还支持锁升级(lock escalation)。
所谓锁升级是指调整锁的粒度,将多个低粒度的锁替换成少数的更高粒度的锁,以此来降低系统负荷。在SQL Server中当一个事务中的锁较多,达到锁升级门限时,系统自动将行级锁和页面锁升级为表级锁。
特别值得注意的是,在SQL Server中,锁的升级门限以及锁升级是由系统自动来确定的,不需要用户设置。

(4) :锁模式 描述

· 共享(S) 用于不更改或不更新数据(只读操作),如SELECT语句

· 更新(U) 用于可更新的资源中。防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁。

· 排它(X) 用于数据修改操作,例如 INSERT、UPDATE或DELETE。确保不会同时对同一资源进行多重更新

· 意向 当 Microsoft SQL Server 数据库引擎获取低级别的锁时,它还将在包含更低级别对象的对象上放置意向锁.例如: 当锁定行或索引键范围时,数据库引擎将在包含行或键的页上放置意向锁。当锁定页时,数据库引擎将在包含页的更高级别的对象上放置意向锁。
意向锁 的类型为:意向共享(IS)、意向排它(IX)以及意向排它共享(SIX)

· 架构 在执行依赖于表架构的操作时使用。架构锁的类型为:架构修改(Sch-M)和架构稳定(Sch-S)

· 大容量更新(BU) 向表中大容量复制数据并指定了TABLOCK提示时使用

(4):

封锁的问题

活琐:

在多个事务请求对同一数据封锁时,系统可能使某个事务永远处于等待状态,而等不到封锁的机会,这种总是处于等待的状态称为活 琐:

解决此的办法:

采用事务排队的方法,先来先服务 ,以使前面的事务先获得对数据的封锁权:

(2)死琐:

指系统中有两个以上的事务处于交错等待状态,每一个等待另

个解除封锁的现象;

解决死锁的两类办法:

一类方法; 是采用一定的措施来预防死琐的发生:

另一类方法:允许先死琐,然后用一定的手段来诊断并予解除:

预防死琐的两个方法: (查资料)

<!--[if !supportLists]-->(1) 一次封琐法:要求每个事务一次将所有要用使用的数据全部加琐,否则不要继续执行,该方法可以预防死锁的发生,但一次性将以后用到的所有数据加琐,扩大了封琐范围,降低了系统的并发度:

<!--[if !supportLists]-->(2) 顺序封琐法:

预先对一个数据对象规定一个封锁的顺序,所有事务按此顺序实行封琐,该方法也可以有效防止,但问题是系统中可封锁的数据对象极多,且随操作而不断的变化,因此其实际操作困难,成本较高

数据库管理系统更常用使用的诊断并解决死锁的方法,该方法也有两种:

1: 超时法:(ex)

2: 等待图法Lex,查资料

附加材料:1 处理死锁和设置死锁优先级
死锁就是多个用户申请不同封锁,由于申请者均拥有一部分封锁权而又等待其他用户拥有的部分封锁而引起的无休止的等 待
可以使用SET DEADLOCK_PRIORITY控制在发生死锁情况时会话的反应方式。
Syntax:
SET DEADLOCK_PRIORITY { LOW | NORMAL}
其中LOW说明该进程会话的优先级较低,在出现死锁时,可以首先中断该进 程的事务。
2 处理超时和设置锁超时持续时间。
@@LOCK_TIMEOUT 返回当前会话的当前锁超时设置,单位为毫秒
SET LOCK_TIMEOUT 设置允许应用程序设置语句等待阻塞资源的最长时间。当语句等待的时间大于 LOCK_TIMEOUT 设置时,系统将自动取消阻塞的语句,并给应用程序返回"已超过了锁请求超时时段"的 1222 号错误信息
示例
1)将锁超时期限设置 为 1,800 毫秒。
SET LOCK_TIMEOUT 1800
2) 配置索引的锁定粒度
可以使用 sp_indexoption 系统存储过程来设置用于索引的锁定粒度
3)设置事务隔离级别
SET TRANSACTION ISOLATION LEVEL

三: 事务的调度(查资料)

事务的执行次序称为(调度)

<!--[if !supportLists]-->(1) 串行调度

<!--[if !supportLists]-->(2) 并发调度

<!--[if !supportLists]-->(3) 可串行化

<!--[if !supportLists]-->(4) 两段琐

五 查看锁的信息
1 执行 EXEC SP_LOCK 报告有关锁的信息
2 查询分析器中按Ctrl+2可以看到锁的信息

七 如何避免死锁
1 使用事务时,尽量缩短事务的逻辑处理过程,及早提交或回滚事务;
2 设置死锁超时参数为合理范围,如:3分钟-10分种;超过时间,自动放弃本次操作,避免进程悬挂;
3 所有的SP都要有错误处理(通过@error)
4 一般不要修改SQL SERVER事务的默认级别。不推荐强行加锁
5 优化程序,检查并避免死锁现象出现;
1)合理安排表访问顺序
2)在事务中尽量避免用户干预,尽量使一个事务处理的任务少些。
3) 采用脏读技术。脏读由于不对被访问的表加锁,而避免了锁冲突。在客户机/服务器应用环境中,有些事务往往不允许读脏数据,但在特定的条件下,我们可以用脏 读。
4)数据访问时域离散法。数据访问时域离散法是指在客户机/服务器结构中,采取各种控制手段控制对数据库或数据库中的对象访问时间段。主要 通过以下方式实现: 合理安排后台事务的执行时间,采用工作流对后台事务进行统一管理。工作流在管理任务时,一方面限制同一类任务的线程数(往往限制为1个),防止资源过多占 用; 另一方面合理安排不同任务执行时序、时间,尽量避免多个后台任务同时执行,另外,避免在前台交易高峰时间运行后台任务
5)数据存储空间离 散法。数据存储空间离散法是指采取各种手段,将逻辑上在一个表中的数据分散到若干离散的空间上去,以便改善对表的访问性能。主要通过以下方法实现: 第一,将大表按行或列分解为若干小表; 第二,按不同的用户群分解。
6)使用尽可能低的隔离性级别。隔离性级别是指为保证数据库数据的完整性和 一致性而使多用户事务隔离的程度,SQL92定义了4种隔离性级别:未提交读、提交读、可重复读和可串行。如果选择过高的隔离性级别,如可串行,虽然系统 可以因实现更好隔离性而更大程度上保证数据的完整性和一致性,但各事务间冲突而死锁的机会大大增加,大大影响了系统性能。
7)使用Bound Connections。Bound connections 允许两个或多个事务连接共享事务和锁,而且任何一个事务连接要申请锁如同另外一个事务要申请锁一样,因此可以允许这些事务共享数据而不会有加锁的冲突。
8) 考虑使用乐观锁定或使事务首先获得一个独占锁定。

1 如何锁一个表的某一行

Java代码

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM table1 ROWLOCK WHERE A = 'a1'
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT * FROM table1 ROWLOCK WHERE A = 'a1'

2 锁定数据库的一个表
select col1 from 表 (tablockx) where 1=1 ;
加锁后 其它人不可操作,直到加锁用户解锁,用commit或rollback解锁

-- A事务先更新table1表,在更新时,对其他事务进行排他begin tranupdate table1 set A='aa' where B='b2';waitfor delay '00:00:30'; --等待30秒commit tran-- A事务先更新table2表begin transelect * from table1 where B='b2';commit tran若同时执行上述两个事务,则select查询必须等待update执行完毕才能执行即要等待30秒

八;死锁:

A事务先更新table1表,然后延时30秒,再更新table2表;begin tranupdate table1 set A='aa' where B='b2';--这将在 Table1 中生成排他行锁,直到事务完成后才会释放该锁。waitfor delay '00:00:30';--进入延时update table2 set D='d5' where E='e1' ;commit tran-- B事务先更新table2表,然后延时10秒,再更新table1表;begin tranupdate table2 set D='d5' where E='e1';--这将在 Table2 中生成排他行锁,直到事务完成后才会释放该锁waitfor delay '00:00:10'--进入延时update table1 set A='aa' where B='b2' ;commit tran若并发执行上述两个事务,A,B两事务都要等待对方释放排他锁,这样便形成了死锁。

九、sqlserver提供的表级锁
sqlserver所指定的表级锁定提示有如下几种
1. HOLDLOCK: 在该表上保持共享锁,直到整个事务结束,而不是在语句执行完立即释放所添加的锁。
2. NOLOCK:不添加共享锁和排它锁,当这个选项生效后,可能读到未提交读的数据或“脏数据”,这个选项仅仅应用于SELECT语句。
3. PAGLOCK:指定添加页锁(否则通常可能添加表锁)
4. READCOMMITTED用与运行在提交读隔离级别的事务相同的锁语义执行扫描。默认情况下,SQL Server 2000 在此隔离级别上操作。
5. READPAST: 跳过已经加锁的数据行,这个选项将使事务读取数据时跳过那些已经被其他事务锁定的数据行,而不是阻塞直到其他事务释放锁,READPAST仅仅应用于 READ COMMITTED隔离性级别下事务操作中的SELECT语句操作
6. READUNCOMMITTED:等同于NOLOCK。
7. REPEATABLEREAD:设置事务为可重复读隔离性级别。
8. ROWLOCK:使用行级锁,而不使用粒度更粗的页级锁和表级锁。
9. SERIALIZABLE:用与运行在可串行读隔离级别的事务相同的锁语义执行扫描。等同于 HOLDLOCK。
10. TABLOCK:指定使用表级锁,而不是使用行级或页面级的锁,SQL Server在该语句执行完后释放这个锁,而如果同时指定了HOLDLOCK,该锁一直保持到这个事务结束。
11. TABLOCKX:指定在表上使用排它锁,这个锁可以阻止其他事务读或更新这个表的数据,直到这个语句或整个事务结束。
12. UPDLOCK :指定在读表中数据时设置更新锁(update lock)而不是设置共享锁,该锁一直保持到这个语句或整个事务结束,使用UPDLOCK的作用是允许用户先读取数据(而且不阻塞其他用户读数据),并且保证在后来再更新数据时,这一段时间内这些数据没有被其他用户修改
SELECT * FROM table WITH (HOLDLOCK) 其他事务可以读取表,但不能更新删除
SELECT * FROM table WITH (TABLOCKX) 其他事务不能读取表,更新和删除

十、应用程序锁

应用程序锁就是客户端代码生成的 锁,而不是sql server本身生成的锁处理应用程序锁的两个系统存储过程
sp_getapplock: 锁定应用程序资源
sp_releaseapplock: 为应用程序资源解锁

十一:

在SQLServer中怎么防止多线程程序同事查询到同一条数据?

现在有个多线程程序不停从任务表查询到未完成的任务发送到客户端,由于是多个线程,我在程序中使用了SQLAPI,SQLAPI中我将连接的 IsolationLevel设为

Read UnCommitted,出现了多个线程获取同一任务的情况,请问几个级别该使用哪个级别?

ReadUncommitted
ReadCommitted
RepeatableRead
Serializable

或者说在数据库这一层上有什么时候可以实现记录锁定,防止 获取同一记录的问题?

一些回答:

select * from table with (rowlock) where a=b

如果是不允许别的线程再读取数据的话,那就加xlock

select * from tb with (xlock,paglock)

paglock还是rowlock看你数据的封锁粒度BEGIN TRANSACTION
SELECT * FROM table WITH (XLOCK ) WHERE ListId = '1' and Reading = 0
update table set Reading = 1
COMMIT TRANSACTION

设置一个标志为来控制你的数据
但是使用XLOCK记得一定要commit或者rollback,都则 会导致表被锁定

十一:举个例子:

  几个例子帮助大家加深印象,设table1(A,B,C)
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3

  1)排它锁
  新建两个连接,在第一个连接中执行以下语句
begin tranupdate table1set A='aa'where B='b2'waitfor delay '00:00:30'
--等待 30秒commit tran

  在第二个连接中执行以下语句
begin transelect * from table1where B='b2'commit tran

  若同时执行上述两个语句,则select查询必须等待update执行完毕才能执行即要等待30秒
  2)共享锁
  在第一个连接中执行以下语句
begin transelect * from table1 holdlock -holdlock人为加锁where B='b2'waitfor delay '00:00:30'
-- 等待30秒commit tran

  在第二个连接中执行以下语句
begin transelect A,C from table1where B='b2'update table1set A='aa'where B='b2'commit tran

   若同时执行上述两个语句,则第二个连接中的select查询可以执行,而update必须等待第一个事务释放共享锁转为排它锁后才能执行 即要等待30秒
  3)死锁
  增设table2(D,E)
D E

d1 e1
d2 e2

   在第一个连接中执行以下语句
begin tranupdate table1set A='aa'where B='b2'waitfor delay '00:00:30'update table2set D='d5'where E='e1'commit tran

   在第二个连接中执行以下语句
begin tranupdate table2set D='d5'where E='e1'waitfor delay '00:00:10'update table1set A='aa'where B='b2'commit tran

   同时执行,系统会检测出死锁,并中止进程
  补充一点:
  SQL Server 2000支持的表级锁定提示
   HOLDLOCK 持有共享锁,直到整个事务完成,应该在被锁对象不需要时立即释放,等于SERIALIZABLE事务隔离级别
   NOLOCK 语句执行时不发出共享锁,允许脏读 ,等于 READ UNCOMMITTED事务隔离级别
  PAGLOCK 在使用一个表锁的地方用多个页锁
  READPAST 让SQL Server跳过任何锁定行,执行事务,适用于READ UNCOMMITTED事务隔离级别只跳过RID锁,不跳过页,区域和表锁
  ROWLOCK 强制使用行锁
  TABLOCKX 强制使用独占表级锁,这个锁在事务期间阻止任何其他事务使用这个表
  UPLOCK 强制在读表时使用更新而不用共享锁
  应用程序 锁:
  应用程序锁就是客户端代码生成的锁,而不是SQL Server本身生成的锁
  处理应用程序锁的两个过程
   sp_getapplock 锁定应用程序资源
  sp_releaseapplock 为应用程序资源解锁
  注意: 锁定数据库的一个表的区别
  SELECT * FROM table WITH (HOLDLOCK) 其他事务可以读取表,但不能更新删除
  SELECT * FROM table WITH (TABLOCKX) 其他事务不能读取表,更新和删除
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: