第章 多用户环境
数据库并不是一个孤岛可以想象这样的场景一个或多个用户都在访问数据库所有的修改和保存都按照一种正确的顺序执行不会陷入混乱在现实中创建数据库通常都是为了实现多人共享数据即使对于桌面型数据库Microsoft Access和OpenOffice BASE也可以通过网络进行共享RDBMS服务器本身就是专门设计用于支持多用户环境的
当一个以上的用户访问同一个数据集时一些新的问题就产生了哪些数据应该对于每一个用户都可见呢?谁的修改应该具有优先权?在执行一个较长的数据库过程期间用什么保证数据的修改不会丢失?为了找到这些问题(以及很多其他问题)的答案下面将介绍会话事务和锁的概念
上面的这些问题可以用RDBMS的术语重新表述为
事务为潜在的数据一致性问题提供了解决方案
锁用于处理数据的并发性问题
会话代表了事务和锁存在的上下文环境
会话
在RDBMS服务器和访问它的一个用户之间发生的任何通信过程都是发生在一个会话的上下文环境中可以将会话视为一个唯一的通道它仅为你打开供你访问数据或者在桌面型数据库的情形下例如Microsoft Access和OpenOffice BASE就是专属于你自己的一个数据文件的副本当你连接到数据库并通过认证时RDBMS将为你自动创建一个会话
在多用户环境中令人担忧的问题之一就是数据的完整性当一个客户端应用程序建立了一个到RDBMS服务器的连接时称为打开了一个会话会话就是该应用程序与服务器进行通信的私有通道在会话期间用户可能修改了一些首选项(例如默认语言或默认数据格式)这些设置仅影响到当前这个特定的用户环境并且仅仅只在该会话期间有效各种RDBMS对会话的实现细节和会话的默认行为可能有所差异但这些基本的原则是保持一致的
本书中使用的工具都是客户端在会话上下文中访问RDBMS服务器的例子对于桌面型数据库则有所不同例如Microsoft Access文件它既可以作为数据存储使用也可以包含很多通常与应用程序相关的对象例如表单报表等(有很多办法可以将这些功能划分到前端和后端文件中)对于Microsoft Access会话就是打开的mdb/accdb文件的一个本地副本在使用完之后必须将其合并回主文件(关于这一话题的更多内容请参考有关Microsoft Access的专业出版物)
OpenOffice BASE的架构与Microsoft Access不同从本质上讲OpenOfficeBASE被设计为一个桌面型的通道为任何支持JDBC驱动程序的数据库提供一个前端它内置的HSQLDB数据库引擎是一个默认的选择嵌入版本的OpenOffice BASE并未设计用于多用户环境
RDBMS为各自的RDBMS服务器都提供了一些命令行工具这是所有RDBMS的共同特性所有RDBMS都提供了一个图形化的用户界面(GUI)另外还有很多第三方工具关于这些工具的更多信息请参考附录C和附录D的内容
SQL标准定义了很多参数可以使用这些参数来连接数据库并在会话期间保持这些参数RDBMS已经实现了其中绝大部分参数尽管在某些元素的实现上使用了私有的语法但是只是语法形式的不同本质是一样的
在Oracle中为了建立一个数据库连接用户必须具有系统特权CREATESESSION;要想修改会话的参数用户必须具有ALTER SESSION特权在初始时会话的所有默认参数都是从一个特殊的Oracle配置文件中加载的只有数据库管理员或者具有必要特权的人才能修改这个配置文件一旦连接建立之后(即创建了会话)用户就可以根据自己的偏好和工作的要求修改会话的参数
IBM DB为会话环境提供了非常少的用户控制它提供了一个SET SESSION AUTHORIZATION语句(遵循SQL标准)和一个等效的SET SESSION_USER语句用于修改会话的上下文
SETPASSTHRU语句为会话提供了最直接的控制它可以为将SQL数据直接提交到数据库打开和关闭一个会话另外在会话期间创建的全局临时表将使用SESSION组件作为限定的模式(在临时表的名称与某个永久表的名称相同的情况下避免在访问表时出现歧义)
当客户端终止了一个会话自发地终止会话或异常地终止会话为会话设置的所有参数都将消失此外对于所有悬而未决的事务在客户端自发地终止会话的情况下将执行一个隐式的提交在会话异常终止的情况下将执行一个回滚
数据库管理员(DBA)可以杀死或断开一个会话但在各个RDBMS中执行该命令的语法存在一定的差别
试一试修改会话参数
Microsoft SQL Server 提供了大量的语句可以修改当前会话的设置这些语句并不是SQL标准的一部分实际上它们是TransactSQL方言的一部分下面的例子将修改其中一个设置ANSI_NULLS并查看该设置对查询输出的影响
() 打开Microsoft SQL Server Management Studio Express连接到LIBRARY数据库
()下面的语句用于从LIBRARY数据库的PHONE表中获取所有BK_PRICE字段不为NULL的记录
SET ANSI_NULLS ON
GO
SELECT bk_title
FROM books
WHERE bk_price <> NULL
GO
( row(s) affected)
() 尽管实际上可以料想到LIBRARY数据库中的所有图书都具有相应的价格表中一定存在满足这一条件的记录但是该查询却没有返回任何记录
() 清除查询窗格中的内容输入新的SQL批语句如下所示
SET ANSI_NULLS OFF
GO
SELECT bk_title
FROM books
WHERE bk_price<> NULL
GO
BK_TITLE
SQL Bible
Steppenwolf
示例说明
由于NULL并不是一个特殊的值它是一个表示缺少值的占位符因此对NULL值应该区别对待SQL标准强制要求凡是涉及NULL值的比较操作总是返回FALSE把MicrosoftSQL Server 的ANSI_NULLS参数调整为ON将指示数据库遵循这一标准但Oracle /g和IBM DB 都没有类似于ANSI_NULLS这样的设置
如果使用更为标准的ISNULL语法就可以完全避免这一情况
SELECT bk_title
FROM books
WHERE bk_price IS NOT NULL
在所有RDBMS中上面这个查询都可以返回正确的结果
返回目录SQL实战新手入门
编辑推荐
Oracle索引技术
高性能MySQL
数据仓库与数据挖掘培训视频教程