INFORMIX使用锁技术解决在多用户访问数据库情况下,对同一对象访问的并发控制问题。INFORMIX支持复杂的、可伸缩性的锁技术。
锁的类型
INFORMIX有三种不同类型的锁。它们在不同的情况下使用。
1. SHARED锁
SHARED锁只保留对象的可读性。当锁存在时,对象不能改变。多个程序可对同个对象加SHARED锁。
2. EXCLUSIVE锁
只能使单个程序使用。在程序要改变对象时使用。当其他锁存在时,EXCLUSIVE锁不能使用。当使用了EXCLUSIVE 锁后,其他锁不能用于同一对象。
3. PROMOTABLE锁
实现更新的目的。PROMOTABLE锁可以放在已经有SHARED锁的记录,但不能放在已经有PROMOTABLE锁和EXCLUSIVE锁的地方。当记录上无其他锁(含SHARED 锁)情况下,这时在程序准备改变锁的记录时,PROMOTABLE锁可以提升为EXCLUSIVE锁。如果在已有SHARED锁的记录上设置了PROMOTABLE锁,在PROMOTABLE锁可以提升到EXCLUSIVE锁之前需要删除SHARED 锁。PROMOTABLE锁只能在INFORMIX Universal Server中支持。
锁的范围
INFORMIX对于数据锁定提供了三种不同的方式,范围由大到小分别是数据库、表、记录级锁。使用的时机要看应用状况而定。
1. 数据库级锁
你可以用CONNECT, DATABASE, 或 CREATE DATABASE语句打开数据库。打开数据库的操作就在数据库上设置了SHARED锁。只要程序打开一个数据库,SHARED锁就会阻止其他程序删除数据库或在数据库上设置EXCLUSIVE锁。你可以用语句DATABASE
database name EXCLUSIVE锁定整个数据库。若此时其他用户正在使用该数据库,该操作将返回错误。
一旦设置了EXCLUSIVE锁,其他程序就不能打开数据库,因为打开时要放置一个SHARED锁。只有数据库关闭时,数据库锁才释放。你可以用DISCONNECT或CLOSE DATABASE显示地处理,也可以运行其他的DATABASE语句隐含的处理。一般数据库级EXCLUSIVE锁是独占数据库资源,防止其他程序访问数据库。它使得程序非常简单,不会产生并发效果。常用在非高峰时期要改变大量数据时如数据库备份过程。
2. 表级锁
INFORMIX提供两种模式表级锁:EXCLUSIVE MODE 和SHARE MODE。你可以锁整个表。在某些情况下,这个操作是自动进行。当INFORMIX处理下列语句时,一般锁整个的表:
ALTER INDEX 、ALTER TABLE 、CREATE INDEX、DROP INDEX 、RENAME COLUMN、RENAME TABLE 。该语句结束或事务结束会释放该锁。在某些查询语句中,INFORMIX也自动锁整个表。
你可以用LOCK TABLE语句显示地锁整个表。该语句允许你对整个表设置EXCLUSIVE锁或SHARED锁。当你程序从表中读取数据时,SHARED锁防止表中数据更新。INFORMIX Universal Server 通过设置隔离级别实现更大程度并发数据保护。
表级EXCLUSIVE锁防止对同个表的并发使用。因此,如果其他许多程序要使用该表时,系统性能会受到严重影响。类似数据库级EXCLUSIVE锁,表级EXCLUSIVE锁常用在非高峰时期要改变大量数据时。例如,有些应用在高峰期间并不更新表,它们可以在非高峰期间定期以批处理方式更新。
通过UNLOCK TABLE table name 解除锁。当存在事务时,事务结束时解除锁。
3. 记录级、页级、键字级锁
表的一个记录是可设置锁的最小对象。一个程序可以锁一个记录或记录的集合,同时其他程序可以操作同一个表的其他记录。Universal Server 以磁盘页面(disk pages)为单位存储数据。一个磁盘页面包含一个或多个记录。在有些情况下,页级锁比单个锁更好些。其他数据库服务器可能不存在页级、键字级锁。
在Universal Server上,当你创建表时,你可以选择使用记录级锁或页级锁。其他的数据库服务器不提供这种选择。页级、记录级锁有相同的效果。当Universal Server需要锁一个记录时,根据表创建时的锁模式,锁这个记录或记录所在的页面。在一定情况下,数据库服务器需要锁一个不存在的记录。它的效果相当于在记录将要存在的地方放一个锁。当表使用记录锁时,对假想的记录使用键字锁。当表使用页级锁时,含有或可能含有键字的索引页将被设置键级锁。
锁的时期
程序控制数据库级锁的时期。数据库关闭时,数据库锁级也就释。表级、记录级、索引级锁的时期依赖于使用的SQL语句以及是否使用事务。如果数据库没有使用事务,也就是说,事务日志不存在并且你没有使用COMMIT WORK语句,当运行UNLOCK TABLE语句时,表级锁就释放。当使用了事务时,事务结束,表级、记录级、索引级锁都释放。修改时锁的处理
当数据库服务器通过一个更新游标取一条记录时,它在该记录上设置一个PROMOTABLE锁。如果这个动作成功,数据库服务器知道其他程序不能改变此记录。因为PROMOTABLE锁不是独占的,其他程序能够继续读这条记录。由于在取此记录的程序执行UPDATE、DELETE语句或简单地取下一条记录之前,它可能花一些时间。这样就提高了性能。当它改变一个记录时,数据库服务器在这条记录上设置一个EXCLUSIVE锁。如果它已经有一个PROMOTABLE锁,它将锁改为EXCLUSIVE状态。
EXCLUSIVE锁的时期依赖于是否使用事务。如果没有使用事务,被修改的记录写到磁盘上就会释放该锁。当使用了事务时,锁就会保持到事务的结束。这个动作防止其他程序使用可能回滚到原来状态的记录。
当使用了事务时,只要删除记录键级锁就会设置。使用键级锁解决下列错误:程序A删除一个记录,程序B插入有同样键的记录。程序A回滚事务,使数据库服务器恢复了删除的记录,这时程序B插入的记录怎么办?通过锁索引,数据库服务器等到程序A提交事务时才插入记录。
由于 Universal Server数据库服务器管理自己的锁,所以它能提供不同类型的锁。其他的数据库服务器是通过操作系统的特性实现锁,所以不能提供多种选择。有些操作系统通过操作系统服务方式向外提供锁函数。在这些系统,数据库支持SET LOCK MODE语句。而有些操作系统不支持内核级的特性,数据库这时通过在数据库目录下产生小文件实现锁。这些文件带有.lok后缀。如果你的程序使用单个SELECT语句或没有用FOR UPDATE声明的游标提取一个记录,此记录不管是否被一个未完成的交易上锁会马上被提取。这样能产生最好的性能。当你使用FOR UPDATE声明的游标时,它在提取前将当前记录上锁。如果当前记录已经有锁,随着选择模式的不同,程序会等待或返回错误。当取下一个记录时,数据库看当前记录是否更新(使用带WHERE CURRENT OF 的UPDATE 锁的模式 )
锁的模式决定程序遇到被锁的数据会产生怎样的结果。当程序要提取或修改一个上锁的记录时,会有下面几种情况:
1、 数据库马上通过SQLCODE变量或SQLSTATE结构给程序返回一个错误代码。
2、 在数据解锁前,数据库将程序挂起。
3、数据库将程序挂起一段时间。如果锁还未解,数据库给程序返回一个错误代码。
你可以通过SET LOCK MODE模式选择以上结果。
如果你喜欢程序等待(对大多数程序而言这是最好的选择),运行下列语句:SET LOCK MODE TO WAIT。
当设置了锁模式后,程序常忽视其他并发程序的存在性。如果程序需要访问其他程序已上锁的记录时,它等待别的程序解锁,然后继续。延迟的时间常不可预测。
等待解锁不利的一面就是可能会等待很长时间。如果不能接受很长延迟,程序可以运行下列语句:SET LOCK MODE TO NOT WAIT选择不等待。当程序需要一个锁记录时,它马上返回一个错误代码,且当前的SQL语句终止。这时,程序必须回滚当前的交易再试一次。程序开始时,数据库初始设置为不等待。
当你使用UNIVERSAL SERVER时,你有另外的选择。你可以让数据库设置等待时间的上限。你可用下列语句:SETLOCK MODE TO WAIT 18让数据库有18秒等待上限。若期间锁还没有解开,将返回错误代码。
在每个程序都选择了锁等待模式情况下,有可能出现死锁。死锁是程序之间相互阻塞,每个程序在其他程序要访问的对象上设置了锁。UNIVERSAL SERVER在单个网络服务器情况下会马上检测到死锁。如果程序选择了锁等待模式,通过给程序返回错误代码,你就知道你遇到了死锁。而在多个数据库服务器的情况下,UNIVERSAL SERVER不能马上检测到。每个数据库服务器都设置锁等待的上限。如果超时,数据库服务器就认为发生了死锁且返回相关的错误代码。数据库管理员可以设置和修改等待时间的上限。