一,NULL与布尔数据类型 Transact-SQL中存在Boolean类型,if 后面的表达式的计算结果一般是Boolean类型,但无法使用 declare 定义Boolean类型的变量.
Boolean数据类型有三种取值,TRUE,FALSE,UNKNOWN,第3种取值通常会被人忽视从而导致逻辑错误. 默认情况下SET ANSI_NULLS为ON,在逻辑表达式中如果你忽略了NULL的存在,结果可能会异于你所想. 例1:?
SQL code
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:
SQL code
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.
二,运行时错误与自动回滚事务 有些人认为一个批查询在执行中发生了错误,这个查询就会中止,其实是错误的.
例1:
SQL code
declare
@i
int
set
@i
=
1
/
0
set
@i
=
1
select
@i
结果会先报一个 服务器: 消息 8134,级别 16,状态 1,行 2 遇到被零除错误。 然后输出结果集 1.
例2:
SQL code
set
xact_abort
on
declare
@i
int
set
@i
=
1
/
0
set
@i
=
1
select
@i
结果只报错,不会输出结果.
例3: 请在查询分析器中新建连接执行
SQL code
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:
SQL code
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
三,字符串相等与排序规则 SQLServer简体中文版默认的排序规则是Chinese_PRC_CI_AS,这种情况下是不区分大小写及宽字符的. 'A' 与 'a' 与 'A'是相等的. 另外字符串比较时尾随空格是被忽略的.(顺便提一下len()也是忽略尾随空格的).
SQL code
if
'
abc
'
=
'
ABc
'
select
1
结果会输出1
宽字符,尾随空格常常被忽视.
四,隐性锁
select 默认情况下会给表加上共享锁并且在执行完成后就释放,insert,update,delete默认情况下会给表加上排它锁并且一直保持到事务结束. 共享锁可以与共享锁,更新锁共存. 排它锁与任何锁都不能共存.
例1: 新建一张表 create table table1 (id int) 在查询分析器中开两个连接 连接1:
SQL code
begin
tran
select
*
from
table1
连接2:
SQL code
insert
into
table1
values
(
1
)
先执行连接1,再执行连接2,都是立即完成.
然后连接1改为:
SQL code
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:
SQL code
while
@@trancount
>
0
rollback
tran
begin
tran
select
*
from
table1
with
(
holdlock
)
连接2:
SQL code
insert
into
table1
values
(
1
)
先执行连接1,连接2会被阻塞. 因为holdlock改变了共享锁的生存期,让共享锁保持到事务结束,而共享锁与排它锁是不能共存的.
连接1改为:
SQL code
while
@@trancount
>
0
rollback
tran
begin
tran
select
*
from
table1
with
(tablockx)
先执行连接1,连接2仍会被阻塞. 这里指定select使用表级排它锁,该锁会保持到事务结束,所以这里不用加holdlock.
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|