找回密码
 注册
搜索
热搜: 超星 读书 找书
查看: 365|回复: 0

[【推荐】] 行级锁实现数据一致性与效率的均衡

[复制链接]
发表于 2010-3-12 08:41:52 | 显示全部楼层 |阅读模式
在数据库维护的过程中,数据库管理员可能有这方面的需求。管理员要求某表中的部分数据暂时只有他自己或者某个特定的用户可以更改,而其他用户则只能够查询。如为了核对数据的需要,要暂时拒绝用户更改某些数据。这就好像在Excel表格中,对某些行进行保护。当某个用户访问这张表格时,其他用户只能够查看表格中的内容,对于受保护的数据,其他用户不能够更改、删除等等。

  在Oracle数据库中可以实现这个需求吗?在数据库中,有多种方式可以实现这种方式。如将这个表所在的表空间设置为只读,或者通过更改权限来完成,设置其他用户对这个表只有只读的权限。但是,这些方法都有点小题大做。如将某个表空间设置为只读,那么任何用户都不能够对其中的数据进行更改;而且如果表空间中有很多表的话,受影响的表格会很多。如通过权限来控制虽然可以减少范围,但是数据库管理员可能只需要保护表中某些数据。即除了受保护的数据之外,其他的用户仍然可以正常访问,如可以删除、更新等等。所以,以上这两种方法虽然可以最终实现这个需求,但是由于其牵涉面太广,会在很大程度上影响其他用户的正常使用。为此这两个方法并不是笔者推荐的方法。笔者推荐的是通过行级锁来完成。下面笔者就将对这个方法进行详细的阐述,特别会强调使用过程中的注意点。

  如现在数据库中有system与victor两个用户,有一个dtm_pro表。现在数据库管理员希望对这张表中的部分数据进行保护。如希望RECID1小于450的记录暂时其他用户不能够更改。其他用户之能够查询这些记录,而不能够删除或者更改。为了减少用户使用数据库的不利影响,数据库管理员要求对于RECID1大于等于450以上的记录,用户可以正常的删除或者更改等等。如下图所示,这就是具体的实现过程。



从上图中可以看出,笔者在查询语句中,加入for update of THREAD# wait 5子句。通过这个子句可以实现行级锁,从而保护结果集中的数据。

  一、行级锁的特征。

  在Oracle数据库中,主要是通过锁来管理共享资源的。简单的说,锁就是控制当有多个用户同时访问相同的共享资源时,彼此对数据的一种额外的权限控制。在Oracle数据库中,锁可以分为行级锁与表级锁。笔者这里要谈的是行级锁。行级锁顾名思义,就是对表中的部分行加锁的一种控制机制。在理解这个行级锁的时候,笔者认为需要注意如下几个方面。

  首先需要注意之所以称为行级锁,就是因为其受影响的范围只是部分的行,而不是表中的全部行。如上例所示,其所影响的行就是where条件所限制的结果级。即只是锁住where条件查询出来的结果集。而对于其他的行不受影响。其他用户可以删除、更改没被加锁的行。通过这种方式,就可以将锁对其他用户的数据库操作的不利影响降低到最低。从而实现效率与安全的并重。

  第二需要注意的是,行级锁是一个排他的所。假设现在上面这两个用户都有对表dtm_pro加锁的权利。在上例中,先由用户system对表中RECID1小于450的记录加了锁。此时其他用户如victor即使其有这个权利,也无法对这张表中的这些记录进行加锁。因为行级锁是排他的。如果硬要加锁的话,则会发生死锁的现象。此时除非数据库管理员人为的利用语句进行解锁,否则的话这个死锁会长时间存在。

  二、行级锁的分类。

  在Oracle数据库中行级锁主要分为两类,一类是自动行级锁。这个自动行级锁是指不需要再语句中采用for update 语句数据库就会自动加锁的方法。这个自动行级锁主要是某些特定的语句所触发的。如现在使用update更新表中的部分数据,在更新完成后事务没有递交之前,数据库会自动对受影响的记录进行加锁,从而实现数据的一致性。这个行级锁虽然是数据库自动增加的,但是往往解锁的时候需要用户手工解锁。即在语句中加入commit(将更新数据写入到数据库中)或者rollback(取消数据的更改)来手工解锁。为此在书写删除或者更新等语句时,一定不要忘记在最后加上一个解锁的语句。否则的话,当其他人也对这些记录进行更新或者删除操作时,会造成死锁的现象。

第二类就是手工加锁。自动加锁只是针对一些更新或者删除操作语句有效,而对于普通的查询语句是无效的。既用户平时在利用select语句查询数据时,是不会对相关的记录加锁的。而现在如果用户需要对某些查询的数据强制加锁的话,那么就需要利用for update 语句手工的为相关的记录进行加锁。当手工加锁之后,与数据库系统自动加锁效果是一样的。加锁后,加锁的用户可以对相关的记录进行删除、更新、查询等操作。而其他用户的话,对这些记录只有查询的权限。同理,当相关的工作完成后,用户要即使的把这个锁解锁掉。系统不会自动对此进行解锁。

  从这里也可以看出锁不一定是数据库系统专用的对象。当用户或者数据库管理员觉得有必要的时候,也可以对某些记录进行手工的加锁,以防止其他用户对这些进行进行更改。当用户觉得某些数据有问题,绝对可能存在弄虚作假的情况,此时对这些受怀疑的数据进行锁定,防止用户对这些数据进行篡改。此时利用这个行级锁就非常的有用。因为此时只对特定的记录进行加锁,而不影响表中其他数据的使用。不过数据库管理员需要注意的是,锁是保护数据安全的一种机制,其跟效率往往是相互冲突的。为此在采用锁的时候,需要注意对于数据库运行效率与用户工作效率可能带来的负面影响。

  三、行级锁使用过程中的注意事项。

  虽然行级锁可以实现对部分数据的保护,但是其毕竟与数据库的工作效率是背道而驰的。为此数据库管理员在管理行级锁的时候,需要注意其对数据库工作效率所造成的负面影响。具体的来说,笔者认为以下三点注意事项要引起大家的重视。

  一是行级锁是排他锁。对于这个排他锁,用户需要了解其两层含意。第一是对于已经锁定的记录,其他用户不能够再在这些记录上加锁。如上例所示,用户system已经对两条记录加锁了,此时用户victor不但不能够修改或者删除数据,也不能够对这些记录重新加锁。这就是排他锁的含义。只有一个用户可以对特定的记录进行加锁。第二是对于已经加锁以外的数据,其他用户仍然可以加锁。如上例中,用户system虽然已经对其中两条记录加锁了,但是用户victor仍然可以利用行级锁对其余的记录进行加锁。所以说,这个排他锁只是对于特定的记录来说的,而不是对整个表格来说的。不同的用户可以在各自的记录上加行级锁,此时记录不能够重复。

  二是需要注意死锁的问题。如上图所示,用户system已经对某些记录加锁了,此时如果用户victor对这些记录也进行加锁操作的话,那么就会造成死锁,因为行级锁是排他锁。当发生死锁现象时,用户victor的会话会一直等待自愿的解锁,如果用户system一百年没有解锁的话,那么victor会一直等待下去。显然这并不是数据库管理员所希望看到的。为此在手工添加行级锁得时候,最好能够添加wati子句。这个子句是用来控制当发生死锁时,会话等待解锁的时间。如果超过这个时间,对方还没有对资源解锁的话,则系统会自动放弃操作,并向用户返回错误信息:资源已经被占用,执行操作时出现Wait错误。可见,假如这个子句的话,可以有效避免死锁对用户会话的不利影响。这个等待的时间用户可以根据自己的需要来设置。不过一般情况下不要把这个时间设置的太长。

  三是在实现行级锁的时候,最好利用where条件语句来限制所影响的记录。如上面例子中,笔者加入了where条件语句,此时最后受行级锁影响的记录只有两条。如果没有加入这个where语句的时候,则整个表的记录都会被加锁了。此时就会对其他用户的操作产生很大的影响,不能够对整个表的数据进行更新、删除等操作。为此在使用行级锁的时候,最好能够将范围限制在最小,即只对必要的记录采用行级锁。从而在保护数据一致性的同时,将其对用户的不利影响降低到最低,提高数据库的运行效率,实现效率与安全的均衡。


http://database.ctocio.com.cn/analysis/209/9388209_1.shtml

推荐:

在数据库维护的过程中,数据库管理员可能有这方面的需求。管理员要求某表中的部分数据暂时只有他自己或者某个特定的用户可以更改,而其他用户则只能够查询。虽然行级锁可以实现对部分数据的保护,但是其毕竟与数据库的工作效率是背道而驰的。为此数据库管理员在管理行级锁的时候,需要注意其对数据库工作效率所造成的负面影响。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|网上读书园地

GMT+8, 2024-11-18 03:42 , Processed in 0.168531 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表