sqlserver 事务
一、实际问题
问:怎么保证两条SQL语句同时执行成功或者同时执行失败?
答:使用事务来保证。
二、举例说明
---例子:一个人要给另一人转账,假设0001号用户只有100块钱,0002号用户有50块钱
-- bank表字段cid、balance
-- 从 0002用户减去100元>50元,显然是要出错,钱不会减少。
update bank set balance=balance-100 where cid='0002'
-- 给0001用户增加100元,但是0001用户缺神奇的多了100元!
update bank set balance=balance + 100 where cid='0001'
-- 如果sql语句执行过程中一条失败了另一条成功了,那银行就很糟糕!
--解决:通过把两个sql语句放到一个事务里,如果任何一条语句发生失败,会回滚到事务内SQL语句执行前的状态。
--步骤:
--1.打开一个事务
begin transaction
declare @sum int =0
--2 执行SQL语句
update bank set balance=balance-100 where cid='0002'
set @sum=@sum+@@error ----在转账之前最好通过if-else判断,不要让程序发生异常或者错误!
update bank set balance=balance + 100 where cid='0001'
set @sum=@sum+@@error
--3 判断,如果有任何一条SQL语句执行出错,那么@@error就不会返回0
if @sum<>0
begin
rollback --4失败则回滚
end
else
begin
commit --5成功,则提交
end
--注意:实际工作中杜绝抛出异常,要把所有的异常都判断到,消灭在if-else中。
三、事务类型:
--1全自动提交事务
--当执行一条sql语句的时候,数据库自动帮我们打开一个事务,当语句执行成功,数据库自动提交事务,执行失败,数据库自动回滚事务。
--insert into bbbb values(fsd) --这条sql语句内部实际就有一个事务。
--2隐式事务,每次执行一条sql语句的时候,数据库自动帮我们打开一个事务,但是需要我们手动提交事务,或者回滚事务。
SET IMPLICIT_TRANSACTIONS { ON | OFF }隐式事务
--打开隐式事务 :自动打开事务,手动提交或回滚事务
SET IMPLICIT_TRANSACTIONS ON
insert into bank values('0003',1000000)
commit
SET IMPLICIT_TRANSACTIONS off
--3显示事务:需要手动打开事务,手动提交事务或者回滚事务。
begin tran --...... commit tran --- rollback transaction ------(如上面的例子)
四、事务的特性
事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性,只有这样才能成为一个事务。
1原子性
事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
2一致性
事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。
3隔离性
由并发事务所作的修改必须与任何其他并发事务所作的修改隔离。事务识别数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是第二个事务修改它之后的状态,事务不会识别中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。
4持久性
事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。