sql事务的使用及其技巧整理

概述:

  在实际项目开发中,为了确保数据操作结果的一致性等要求,事务是一个必不可少的解决利器。

  根据sqlserver实现原理,其实,sqlserver的每一条执行语句都是一个事务操作,也就是说每一个sql语句要么操作都成功,要么操作都失败:比如,更新语句,同时更新多个字段,不会出现有的字段更新成功,有的字段更新失败。

  但是,我们平时在开发过程过程中,说的事务:其实是指的一组有序的sql集合,通过事务确保这一组sql集合执行结果的一致性。

 

事务特性:

  事务的主要特性包括:原子性、一致性、隔离性、持久性

  1.  原子性:事务必须是一个自动工作的单元,要么全部执行,要么全部不执行。
  2.  一致性:事务把数据库从一个一致状态带入到另一个一致状态,事务结束的时候,所有的内部数据都是正确的。
  3. 隔离性:并发多个事务时,一个事务的执行不受其他事务的影响。
  4.  持久性:事务提交之后,数据是永久性的,不可再回滚,不受关机等事件的影响

事务分类:

  根据事务的执行维度力度,事务又分为:自动提交事务、显式事务、隐式事务

   自动提交事务:sqlserver的一种默认机制,也叫自身事务,每一个sql语句执行都是采用的这种模式
   显式事务:这也是我们平时常说的事务, 通过 begin transaction开启事务开始,执行一组sql语句,由commit transaction 提交事务、rollback transaction 回滚事务结束。
   隐式事务:使用set implicit_transactions on 将隐式事务模式打开,sql执行完毕自动提交,当一个事务结束,这个模式会自动启用下一个事务,只用commit transaction 提交事务、rollback transaction 回滚事务即可

   显示事务和隐式的主要区别自在于,隐式事务在执行完毕后自动提交。

显式事务使用简介:

  显示事务通过begin transaction 开启事务,通过rollback transaction 回滚事务

  数据准备,首先创建一个表:  

---- 创建一个表test_name ,每一个字段都是非空
create table [dbo].[test_name](
	[id] [int] null,
	[name] [nvarchar](50) null
) on [primary]

 

  实例:

---- 正常完整的执行一个事务,且事务内sql无异常
---- 正常完整的执行一个事务,且事务内sql无异常
begin tran
insert into test_name values(1,1)
insert into test_name values(3,3)
commit tran
---- 执行一个事务,且事务内sql有异常

begin tran insert into test_name values(10,10) insert into test_name values(11,null)----次语句执行失败,原因是该name不允许为空 insert into test_name values(12,12) commit tran

----- 语句最终执行结果是
成功插入id为:10、12的两条数据

  通过上面的语句,这样的执行结果和我们事务中的一致性相违背,这不是我们使用事务想要看到的效果,其实我们希望的是这3个语句要么都插入成功,要么都插入失败

 为了达到数据,可以通过以下三种方式来实现:try catch;执行结果判断,一步一步执行,错误回滚;开启 xact_abort(精准终止)

  try catch 实现事务回滚

begin tran
begin try
    insert into test_name values(1,1)
    insert into test_name values(2,null)
    insert into test_name values(3,2)
    commit tran
end try
begin catch
    select '执行异常,事务回滚'
    rollback tran
end catch
---- 执行结果是:不会插入一条数据

  

   执行结果判断,一步一步执行,错误回滚

begin tran
    declare @error int 
    set @error=0
    
    insert into test_name values(1,1)
    set @error=@error+@@error
    insert into test_name values(2,null)
    set @error=@error+@@error
    insert into test_name values(3,2)
    set @error=@error+@@error
    
if(@error<>0)
    begin 
        select '执行异常,事务回滚'
        rollback tran
    end
else 
    begin
        commit tran
    end

 

---- 每一步执行结果都正确才继续往下执行
begin tran
    ---- 影响行数
    declare @rowcount int
    set @rowcount=0
    
    insert into test_name values(1,1)
    set @rowcount=@@rowcount
    if(@rowcount>0)
        begin 
            insert into test_name values(2,null)
            set @rowcount=@@rowcount
        end
        
    if(@rowcount>0)
        begin 
            insert into test_name values(3,2)
            set @rowcount=@@rowcount
        end
        
if(@rowcount<=0)
    begin 
        select '执行异常,事务回滚'
        rollback tran
    end
else 
    begin
        commit tran
    end

 

开启 xact_abort(精准终止)
---- xact_abort 设置 on :代表某一个语句执行错误,都不在继续往下执行,并自动回滚事务
---- xact_abort 设置 off :代表某一个语句执行错误,子回滚该条语句执行,并继续执行后续语句,同时提交执行成功的语句
  ---- off 此种情况应该很少在事务中使用,毕竟使用事务的目的就是实现执行结果的一致性
set xact_abort on begin tran insert into test_name values(10,10) insert into test_name values(11,null)----次语句执行失败,原因是该name不允许为空 insert into test_name values(12,12) commit tran

 

设置事务保存点:

  在平时的事务使用过程中,还有可能需要实现,事务回滚时,只回滚到指定位置,指定位置之前的执行结果不在回滚

  在sqlserver中可以通过事务保存点,来实现对事务的精确回滚,关键词是:save transaction   和rollback transaction ,具体使用规则如下:

 

---- 每一步执行结果都正确才继续往下执行
begin tran
    ---- 影响行数
    declare @rowcount int
    set @rowcount=0
    
    insert into test_name values(1,1)
    set @rowcount=@@rowcount
    save tran stanstation1
    --- save tran transtation1
    if(@rowcount>0)
        begin 
            insert into test_name values(2,null)
            set @rowcount=@@rowcount
        end
        
    if(@rowcount>0)
        begin 
            insert into test_name values(3,2)
            set @rowcount=@@rowcount
        end
        
if(@rowcount<=0)
    begin 
        select '执行异常,事务回滚'
        ---- 执行结果是:1,1 成功插入到数据库表中
        rollback tran stanstation1
    end
else 
    begin
        select '事务提交'
        commit tran
    end

 

 总结:

  通过上面的温习,结合练习,对sql的事务有了进一步的了解。简单的总结:实际上执行的每一个sql都是采用事务来实现的,在实际使用中,我们一般采用显示事务来处理业务,但是在事务的使用过程中一定要结合对应的策略来确保事务执行结果的一致性。

  今天就写到这,明天再简单那梳理总结一下分布式事务的实现方式,这个也是很重要的模块,尤其是在现在的大型系统中,分库分表时,分布式事务很管用







xact_abort