在SQLServer事务和锁的详细解析

前几天在SQLServer2005 和SQL Server 2008高级编程编程入门经典(第三版)这两个翻译版本的书中,它被发现的目录结构是大致相同的,和解释的内容几乎是相同的。那里是一个抄袭的嫌疑。当你看到事务和锁,我们发现小实例的形式是相同的。哈哈 u3002 u3002 u3002i不想让这样的书太多评论。翻译版本的书籍在中国。是真的,大部分的翻译有点僵硬。和那些原创作品。他们中的大多数都是抄袭和空话。微软的技术体系,如直接从MSDN或复制本书啊在线,然后就贴几页的代码,可以发布销售,我可以写,因为它没有水平。

当然,也不乏优秀的作品,但是很少也很难找到。好吧,开始谈交易和锁,很难理解数据库中的东西。


一、脏读,不可重复读,幻读

(1)脏读:脏读意味着当事务访问数据并修改数据时,修改尚未提交到数据库。同时,另一个事务也访问数据,然后使用数据。

例如:

张三的薪水是5000,商务部把他的薪水改为8000,但是交易A还没有提交。

Meanwhile,

交易B在读张三的工资,张三的工资是8000。

然后,

交易A是不正常的,交易被回滚,张三的工资被回滚到5000。

去年,uff0c

事务B读取到三工资中的8000的数据是脏数据,事务b做了一个脏读。

(2)不可重复读:是指在一个事务读取同一数据多次。当这个交易还没有结束,另一个事务访问相同的数据。在第一个事务读取数据,两者之间,从第一个交易数据读取两次可能由于二交易修改是不同的。这一切发生的时候,那是在一个事务读取两倍的数据是不同的,所以称为不可重复读取。

例如:

在事务A中,读取给张三的工资为5000,操作未完成,事务未提交。

同时 uff0c

商务B把张三的薪水改为8000,并提交了业务。

然后,

在交易A中,再次读取张三的工资,工资改为8000。交易前后两次读的结果不被诱导,导致不可重复的读数。

(3)影像阅读:这一现象发生时,交易不是独立执行,例如,第一个事务修改表中的数据,包括表中的所有数据行。同时,第二交易也修改表中的数据,这是插入一行插入表中新的数据。然后,在未来,经营第一交易用户没有修改的数据行的表中,如果出现了一个幻觉。

例如:

目前,有10名员工的工资为5000,阅读5000的工资的人数是10。

此时,

交易B插入了工资的5000的记录。

这是,交易A再次读取了5000名员工的工资,记录为11人。

不可重复阅读的关键是修改:
同样的条件,读取的数据再次读取并发现值不同。
幻影阅读的重点是添加或删除:
在相同的条件下,第一次和第二次读取的记录数是不同的。

独家锁,共享锁,更新锁,乐观锁,悲观锁

1、锁的两种分类方法

(1)从数据库系统的角度来看,锁分为以下三种类型:

互斥锁(独占锁)
独占锁锁定的资源只允许程序进行锁定操作,并对它的任何其他操作将不被接受。当数据更新命令后,即插入、更新或删除命令,SQL Server将自动使用独占锁。但当这其他对象的锁,它是不可能加独占锁,独占锁不能直到交易结束发布。

共享锁(共享锁)
共享锁锁定资源可以由其他用户读取,但其他用户不能修改它。当选择命令执行时,SQL Server通常是对象上的共享锁锁。当读取共享锁的数据页时,共享锁立即释放。

更新锁(更新锁)
更新锁设置防止死锁。当SQL Server正在准备更新数据,它首先锁定的数据对象的更新锁,数据不能修改,但可以读取。当SQL Server决定更新数据的操作,它会自动更改更新锁独家锁。但当物体上有其他锁,不能锁在更新锁。

(2)从程序员的角度来看,锁分为以下两种类型:

悲观锁(悲观锁)
悲观锁,正如其名,是指保守态度被外界修改数据,包括系统中的其他交易和外部系统的事务处理,所以数据被锁定在数据处理的全过程。悲观锁,锁机制往往依靠数据库提供的锁机制(数据库层提供了独家的,否则,数据访问真正的保证即使在本系统中实现了锁紧机构,不能保证外部系统不修改数据)。

乐观锁(乐观锁)
在相对悲观锁,乐观锁机制采取了更加宽松的锁定机制。大部分的悲观锁,取决于数据库确保手术最大的垄断锁机制。但随之而来的是大量的开销在数据库的性能,特别是长时间的交易,这是经常无法忍受的。

乐观锁机制在一定程度上解决了这个问题,乐观锁主要基于数据版本(版本)记录机制,数据版本是什么也就是向数据添加版本标识。基于解决方案的数据库版本,它通常是通过向数据库表添加一个版本字段来实现的。当数据被读出,版本号为齐读,然后是版本号增加当更新更新。此时,所提交的数据的版本数据与对应的数据库表的当前版本信息的比较。如果提交的数据的版本号大于数据库表的当前版本号,它将被更新,否则将被认为是过时的。

2。如何在数据库中使用锁

首先,从悲观锁。在许多其他SQLServer数据库,数据锁通常使用页级锁,也就是说在一个表中的数据是一系列的更新机制,在任何时间同一张表只会插入1个数据,其他的要插入数据,直到这一为了完成将数据插入到。降低性能的后果,当多用户访问,当频繁的操作台上,会发现响应效率很低,经常处于假死的数据库状态。Oracle使用行级锁只锁,需要的数据,其余的数据都是无关紧要的,所以这是插在Oracle表的数据几乎没有影响。

注意:悲观锁的可能性更可能是针对并发性的,但在应用程序中使用乐观锁通常是足够的。

Oracle的悲观锁需要使用现有连接分为两种方式。从SQL语句之间的差异的角度,一个是更新,另一个是更新NOWAIT形式。例如,让我们看一个例子。

首先,为测试设置数据库表:

创建测试表(ID、名称、位置、价值、约束test_pk主键(ID))

在这里,我们利用Oracle示例史葛用户的表,并将数据副本放入测试表中。

(1)介绍更新的形式

然后让我们看看更新锁:

从更新ID = 10的测试中选择*

此查询的锁后,SQL * Plus操作打开另一个窗口,然后上面的SQL语句执行,你会发现目前似乎死在那里,如果没有检索到的数据,但没有返回任何结果,它属于卡在那里。在这个时间的原因是什么,是选择在第一届将数据更新语句。由于锁定这里的机制是等待状态(只要不表达不等待,这是等待),所以第二会话的当前检索(即在SQL * Plus)是在等待状态。当第一会议是在提交或回滚结束,第二届结果自动跳出来的数据锁定。

但是,如果您搜索第二个会话,您可以看到您的搜索语句如下:从id = 10的测试中选择*,也就是说,没有更新这样一个数据锁定语句,那么它不会造成阻塞。

(2)更新NOWAIT的形式介绍

另一个案例中,当数据库中的数据是锁着的,也就是说,在执行SQL更新只是现在,当我们执行另一个会话更新不等待我们做什么

例如,下面的SQL语句:

SELECT * FROM测试id是10更新不等待

因为这句话是在立即模式检索制定的,所以当数据是由其他会话锁定,它将很快恢复ora-00054误差。内容资源忙,但资源是NOWAIT方式指定的。所以在节目中,我们可以使用NOWAIT迅速判断当前数据锁定。如果我们锁定它,我们应该采取相应的商业措施来处理它。

这里的另一个问题是当我们锁定数据、更新和删除数据时会是什么样子。

例如,让第一个会话锁定id = 10的数据,然后在第二个会话中执行以下语句:

在id = 10中更新测试集值=2

这时,我们发现UPDATE语句就像更新语句的SELECT语句一样。它也停止卡在这里。当第一个会话被释放时,更新将正常运行。运行更新时,数据将被UPDATE语句锁定。此时,如果在更新后没有提交,则其他会话无法锁定和更新数据。

总之,oracle中的悲观锁是利用oracle的连接来锁定数据,在Oracle中,这种行级锁造成的性能损失非常小。只是要注意程序的逻辑,而不给你一个粗心的僵局,因为及时锁定数据,在数据提交的时间不冲突,所以很多烦人的数据冲突可以保存。缺点是你必须有一个数据库连接,也就是说到最后,锁定解锁的整个过程中,你应该始终保持数据库连接。

与悲观锁相比,我们有一个乐观锁,在乐观锁开始时,假设开始时没有数据冲突,并且在最后一次提交结束时进行数据冲突检测。

在乐观锁中,我们有3种常见的实践来实现:

第一种方法是在获取数据时将整个数据复制到应用程序,并比较当前数据库中的数据和提交时更新之前获得的数据。

当发现两个数据完全相同时,不存在可以提交的冲突,否则是需要由业务逻辑解决的并发冲突。

第二种乐观锁是使用在Hibernate中使用的版本戳。

如果使用版本戳,首先需要在数据库表上用乐观锁构建一个新列,例如,数字。每次更新数据时,版本数量将增加1。

例如,2个会话也对某些数据进行操作,它们都将当前数据的版本号为1。当第一次更新数据,这表明当前数据的版本是1,在提交时,它是作为原始版本开始一样。这是正式提交,然后版本号增加1,此时数据的当前版本是2。当第二届已更新的数据库版本2的发现提交的数据,和会话开始的版本号是不一样的,我知道其他人更新的数据,这段时间来处理业务,如事务回滚操作。

当使用版本戳时,您可以使用应用程序端的版本验证或数据库端的触发器(触发器)来验证它。但是,数据库中触发器的性能开销比较大,所以建议在应用程序上验证它时不推荐使用Trigger。

第三种方式有点类似于第二种方式,即添加一个新的表列,但是这个时间列使用时间戳类型来存储最后一次数据。

在Oracle9i数据库,你可以使用一个新的数据类型,即,随着时间的推移,带型的时间戳来做时间戳。戳数据精度最高的Oracle类型的时间,精确到微秒(不到纳秒量级),总的来说,加上数据库的处理时间和人的思想和作用时间,微秒级是很不够的,事实上,只要是精确到秒甚至几秒钟应该有什么问题。

与以前的版本类似,它还检查当前数据库中的时间戳,并更新更新提交数据之前更新的时间戳。如果一致性是好的,否则将是版本冲突。如果您不想在程序中编写代码,或者由于其他原因无法将代码写入现有程序,也可以在触发器或存储过程中编写这个时间戳乐观锁逻辑。

三,事务五隔离级别

隔离属性支持五个事务设置,如下所示:

(1)违约

使用数据库设置的隔离级别(默认值),隔离级别由DBA的默认设置决定。

(2)read_uncommitted

这是允许外部事务查看事务未提交数据的最低隔离级别。

会有脏读、不可重复读,不读(最低的隔离级别,高并发性能)。

(3)read_committed

确保在另一个事务读取之前由事务修改的数据提交。另一个事务不能读取事务的未提交数据。

你可以避免脏读,但会有一个不可重复的,虚幻的阅读问题(锁线正在读)。

(4)repeatable_read

你可以防止脏读和不可重复读,但你可以阅读的幻想(锁定所有行读)。

(5)序列化

这是最高的成本,但却是最可靠的事务隔离级别,事务处理是为了执行。

确保所有条件都不会发生(锁定表)。