SQLServer陷阱/问题
来源:互联网 发布:网络医院男科可靠吗 编辑:程序博客网 时间:2024/04/30 11:40
http://topic.csdn.net/u/20080610/15/eba066c7-ae6c-47ea-98f4-aa35ebc5ad90.html
本文旨在指出一些在使用SQLServer过程中容易犯的错误, 希望能给您带来帮助.
若没有特殊说明, 本文是指在MS SQLServer 2000简体中文版的默认配置环境中.
一, NULL与布尔数据类型
Transact-SQL中存在Boolean类型, if 后面的表达式的计算结果一般是Boolean类型, 但无法使用 declare 定义Boolean类型的变量.
Boolean数据类型有三种取值,TRUE, FALSE, UNKNOWN, 第3种取值通常会被人忽视从而导致逻辑错误.
默认情况下SET ANSI_NULLS为ON, 在逻辑表达式中如果你忽略了NULL的存在, 结果可能会异于你所想.
例1:
declare @a intif (@a > 0) set @a = 1else if not (@a > 0) set @a = 2else set @a = 3结果@a的值应该是3, 因为NULL>0的值为UNKNOWN, NOT UNKNOWN的值还为UNKNOWN.
例2:
declare @a intif @a = null set @a = 1else if @a = null or 1 = 1 set @a = 2else set @a = 3
结果@a的值应该是2, 因为NULL = 0的值为UNKNOWN, UNKNOWN or TRUE的值为TRUE.
二, 运行时错误与自动回滚事务
有些人认为一个批查询在执行中发生了错误, 这个查询就会中止, 其实是错误的.
declare @i intset @i = 1 / 0set @i = 1select @i结果会先报一个
服务器: 消息 8134,级别 16,状态 1,行 2
遇到被零除错误。
然后输出结果集 1.
例2:
set xact_abort ondeclare @i intset @i = 1 / 0set @i = 1select @i
结果只报错, 不会输出结果.
例3:
请在查询分析器中新建连接执行
create table table1(id int primary key)begin traninsert into table1 values (1)insert into table1 values (1)insert into table1 values (2)commit tran第二个insert会产生违反主键约束错误, 但是执行结束后你会发现事务已经提交并且table1中已经有两行记录1与2
例4:
set xact_abort oncreate table table2(id int primary key)begin traninsert into table2 values (1)insert into table2 values (1)insert into table2 values (2)commit tran执行结束后, table2中没有记录, 说明事务已经回滚.
当 SET XACT_ABORT 为 ON 时,如果 Transact-SQL 语句产生运行时错误,整个事务将终止并回滚。为 OFF 时,只回滚产生错误的 Transact-SQL 语句,而事务将继续进行处理。编译错误
(如语法错误)不受 SET XACT_ABORT 的影响。
一般批查询中 SET XACT_ABORT 默认为 OFF, 隐式开启的事务如触发器中SET XACT_ABORT 默认为ON
三, 字符串相等与排序规则
SQLServer简体中文版默认的排序规则是Chinese_PRC_CI_AS, 这种情况下是不区分大小写及宽字符的.
'A' 与 'a' 与 'A'是相等的.
另外字符串比较时尾随空格是被忽略的.(顺便提一下len()也是忽略尾随空格的).
if 'abc' = 'ABc ' select 1结果会输出1
宽字符,尾随空格常常被忽视.
四, 隐性锁
默认情况下select会使用共享锁, 在数据读取完后会立即释放; insert, update, delete会对更改的数据使用排它锁并且一直保持到事务结束.
共享锁可以与共享锁,更新锁共存. 排它锁与任何锁都不能共存.
“通常,读操作获取共享锁,写操作获取排它锁。在更新操作的初始阶段读取数据时,会获取更新锁。更新锁与共享锁兼容。此后,如果更改了数据,更新锁会提升为排它锁。有时在更改数据时,会在获取排它锁之前暂时获取更新锁。此后,该更新锁会自动提升为排它锁。”
例1: 新建一张表 create table table1 (id int), 加入一条记录 insert into table1 values(1)
在查询分析器中开两个连接
连接1:
begin transelect * from table1连接2:
update table1 set id = 1先执行连接1, 再执行连接2, 都是立即完成.
然后连接1改为:
while @@trancount > 0 rollback tran --如果有未提交的事务就回滚begin tranupdate table1 set id = 1连接2不变
先执行连接1, 再执行连接2, 会发现连接2被阻塞.
这时在连接1中单独执行commit tran, 连接2会立即结束. 注:在测试过程中可以用select @@spid查看当前连接的spid, 用sp_lock查看锁信息.
如果要改变隐性锁, 可以使用with关键字.
例2:
连接1:
while @@trancount > 0 rollback tranbegin transelect * from table1 with(holdlock)连接2:
update table1 set id = 1先执行连接1, 再执行连接2, 连接2会被阻塞. 因为holdlock改变了共享锁的生存期, 让共享锁保持到事务结束, 而共享锁与排它锁是不能共存的.
连接1改为:
while @@trancount > 0 rollback tranbegin transelect * from table1 with(tablockx)先执行连接1, 再执行连接2, 连接2仍会被阻塞. 这里指定select使用表级排它锁, 该锁会保持到事务结束, 所以这里不用加holdlock.
例3:
连接1:
while @@trancount > 0 rollback traninsert into table1 values(2)begin tranupdate table1 set id = 3 where id = 2连接2:
select * from table1先执行连接1, 再执行连接2, 连接2会被阻塞.
连接2:
select top 1 * from table1再执行连接2, 连接2会立即结束. 这里update的过程应该先是查询id=2的记录, 查询时使用共享锁, 不满足id=2的记录共享锁立即释放, 满足id=2的记录把共享锁升级为排它锁并保持到事务
结束. 所以第一次执行连接2会因为无法获取id=2的记录的共享锁而被阻塞, 而第二次执行不会被阻塞.
- SQLServer陷阱/问题
- SQLServer陷阱
- SQLServer陷阱
- 【陷阱系列】SQLServer in/not in 陷阱
- SQLServer陷阱(四) 隐性锁
- SQLServer陷阱(一) NULL与布尔数据类型
- 面试陷阱问题巧做答
- 彩票问题陷阱
- inline陷阱问题
- SQLSERVER问题
- sqlserver问题
- 系统管理工具包: 问题和陷阱
- IMDG中的陷阱和问题
- mysql group_concat()函数陷阱问题
- SQLServer陷阱(三) 字符串相等与排序规则
- “陷阱”
- 陷阱!!!!!!!!!
- SqlServer密码问题(原创)
- Facebook第2名大陆工程师:我对Facebook上市的几点感受
- 常见Web技术之间的关系,你了解多少?
- poj 1015Jury Compromise
- windows下编译boost库
- 蓝牙聊天室(Android版)
- SQLServer陷阱/问题
- ubuntu10.10环境下CTS搭建
- CDMA无线终端上网设置方法
- C#编程中的66个好习惯
- 实战jquery(2)-自建可拖拽模态对话框
- 关于Linux操作系统下C语言编程注意事项
- base-file
- virtualBox 与 centos 实现文件共享
- 在MFC对话框中添加状态栏