SQLServer陷阱/问题
看到有用的文章,转载一下学习一下,原文见如下:
http://topic.csdn.net/u/20080610/15/eba066c7-ae6c-47ea-98f4-aa35ebc5ad90.html 本文旨在指出一些在使用SQLServer过程中容易犯的错误,希望能给您带来帮助. 例1:
declare @a int if (@a > 0) set @a = 1 else if not (@a > 0) set @a = 2 else set @a = 3结果@a的值应该是3,因为NULL>0的值为UNKNOWN,NOT UNKNOWN的值还为UNKNOWN. 例2: declare @a int if @a = null set @a = 1 else if @a = null or 1 = 1 set @a = 2 else set @a = 3 结果@a的值应该是2,因为NULL = 0的值为UNKNOWN,UNKNOWN or TRUE的值为TRUE. 二,运行时错误与自动回滚事务
declare @i int set @i = 1 / 0 set @i = 1 select @i结果会先报一个 服务器: 消息 8134,级别 16,状态 1,行 2 遇到被零除错误。 然后输出结果集 1. 例2:
set xact_abort on declare @i int set @i = 1 / 0 set @i = 1 select @i 结果只报错,不会输出结果. 例3: 请在查询分析器中新建连接执行 create table table1(id int primary key) begin tran insert into table1 values (1) insert into table1 values (1) insert into table1 values (2) commit tran第二个insert会产生违反主键约束错误,但是执行结束后你会发现事务已经提交并且table1中已经有两行记录1与2 例4:
set xact_abort on create table table2(id int primary key) begin tran insert 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 三,字符串相等与排序规则
if 'abc' = 'ABc ' select 1结果会输出1 宽字符,尾随空格常常被忽视. 四,隐性锁 默认情况下select会使用共享锁,在数据读取完后会立即释放; insert,update,delete会对更改的数据使用排它锁并且一直保持到事务结束.
begin tran select * from table1连接2:
update table1 set id = 1先执行连接1,再执行连接2,都是立即完成. 然后连接1改为:
while @@trancount > 0 rollback tran --如果有未提交的事务就回滚 begin tran update table1 set id = 1连接2不变 先执行连接1,会发现连接2被阻塞. 这时在连接1中单独执行commit tran,连接2会立即结束. 注:在测试过程中可以用select @@spid查看当前连接的spid,用sp_lock查看锁信息. 如果要改变隐性锁,可以使用with关键字. 例2: 连接1: while @@trancount > 0 rollback tran begin tran select * from table1 with(holdlock)连接2: update table1 set id = 1先执行连接1,连接2会被阻塞. 因为holdlock改变了共享锁的生存期,让共享锁保持到事务结束,而共享锁与排它锁是不能共存的. 连接1改为: while @@trancount > 0 rollback tran begin tran select * from table1 with(tablockx)先执行连接1,连接2仍会被阻塞. 这里指定select使用表级排它锁,该锁会保持到事务结束,所以这里不用加holdlock. 例3: 连接1:
while @@trancount > 0 rollback tran insert into table1 values(2) begin tran update table1 set id = 3 where id = 2连接2:
select * from table1先执行连接1,连接2会被阻塞. 连接2: select top 1 * from table1再执行连接2,连接2会立即结束. 这里update的过程应该先是查询id=2的记录,查询时使用共享锁,不满足id=2的记录共享锁立即释放,满足id=2的记录把共享锁升级为排它锁并保持到事务 结束. 所以第一次执行连接2会因为无法获取id=2的记录的共享锁而被阻塞,而第二次执行不会被阻塞. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |