SQL Server 事务,异常和游标详解

目录
  • 事务
    • 1、 事务的特点
    • 2、 事务的模式
    • 3、 事务处理
    • 4、 事务的示例
  • 异常
    • 错误函数
    • 示例:用异常处理错误信息
    • 示例:异常能处理的错误信息
    • 示例:无法提交的事务
    • 示例:处理异常日志信息
  • 游标
    • 1、游标实际上是一种能从多条数据记录的结果集中每次提取一条记录的机制。
    • 2、游标的基本操作
    • 3、游标操作示例
  • 总结

事务

在数据库中有时候需要把多个步骤的指令当作一个整体来运行,这个整体要么全部成功,要么全部失败,这就需要用到事务。

1、 事务的特点

事务有若干条T-SQL指令组成,并且所有的指令昨晚一个整体提交给数据库系统,执行时,这组指令要么全部执行完成,要么全部取消。因此,事务是一个不可分割的逻辑单元。

事务有4个属性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)以及持久性(Durability),也称作事务的ACID属性。

原子性:事务内的所有工作要么全部完成,要么全部不完成,不存在只有一部分完成的情况。

一致性:事务内的然后操作都不能违反数据库的然后约束或规则,事务完成时有内部数据结构都必须是正确的。

隔离性:事务直接是相互隔离的,如果有两个事务对同一个数据库进行操作,比如读取表数据。任何一个事务看到的所有内容要么是其他事务完成之前的状态,要么是其他事务完成之后的状态。一个事务不可能遇到另一个事务的中间状态。

持久性:事务完成之后,它对数据库系统的影响是持久的,即使是系统错误,重新启动系统后,该事务的结果依然存在。

2、 事务的模式

a、 显示事务

显示事务就是用户使用T-SQL明确的定义事务的开始(begin transaction)和提交(commit transaction)或回滚事务(rollback transaction

b、 自动提交事务

自动提交事务是一种能够自动执行并能自动回滚事务,这种方式是T-SQL的默认事务方式。例如在删除一个表记录的时候,如果这条记录有主外键关系的时候,删除就会受主外键约束的影响,那么这个删除就会取消。

可以设置事务进入隐式方式:set implicit_transaction on;

c、 隐式事务

隐式事务是指当事务提交或回滚后,SQL Server自动开始事务。因此,隐式事务不需要使用begin transaction显示开始,只需直接失业提交事务或回滚事务的T-SQL语句即可。

使用时,需要设置set implicit_transaction on语句,将隐式事务模式打开,下一个语句会启动一个新的事物,再下一个语句又将启动一个新事务。

3、 事务处理

常用T-SQL事务语句:

a、 begin transaction语句

开始事务,而@@trancount全局变量用来记录事务的数目值加1,可以用@@error全局变量记录执行过程中的错误信息,如果没有错误可以直接提交事务,有错误可以回滚。

b、 commit transaction语句

回滚事务,表示一个隐式或显示的事务的结束,对数据库所做的修改正式生效。并将@@trancount的值减1;

c、 rollback transaction语句

回滚事务,执行rollback tran语句后,数据会回滚到begin tran的时候的状态

4、 事务的示例

begin transaction tran_bank;
declare @tran_error int;
    set @tran_error = 0;
    begin try
        update bank set totalMoney = totalMoney - 10000 where userName = 'jack';
        set @tran_error = @tran_error + @@error;
        update bank set totalMoney = totalMoney + 10000 where userName = 'jason';
        set @tran_error = @tran_error + @@error;
    end try
    begin catch
        print '出现异常,错误编号:' + convert(varchar, error_number()) + ', 错误消息:' + error_message();
        set @tran_error = @tran_error + 1;
    end catch
if (@tran_error > 0)
    begin
        --执行出错,回滚事务
        rollback tran;
        print '转账失败,取消交易';
    end
else
    begin
        --没有异常,提交事务
        commit tran;
        print '转账成功';
    end
go

异常

在程序中,有时候完成一些Transact-SQL会出现错误、异常信息。如果我们想自己处理这些异常信息的话,需要手动捕捉这些信息。那么我们可以利用try catch完成。

TRY…CATCH 构造包括两部分:一个 TRY 块和一个 CATCH 块。如果在 TRY 块中所包含的 Transact-SQL 语句中检测到错误条件,控制将被传递到 CATCH 块(可在此块中处理该错误)。

CATCH 块处理该异常错误后,控制将被传递到 END CATCH 语句后面的第一个 Transact-SQL 语句。如果 END CATCH 语句是存储过程或触发器中的最后一条语句,控制将返回到调用该存储过程或触发器的代码。将不执行 TRY 块中生成错误的语句后面的 Transact-SQL 语句。

如果 TRY 块中没有错误,控制将传递到关联的 END CATCH 语句后紧跟的语句。如果 END CATCH 语句是存储过程或触发器中的最后一条语句,控制将传递到调用该存储过程或触发器的语句。

TRY 块以 BEGIN TRY 语句开头,以 END TRY 语句结尾。在 BEGIN TRY 和 END TRY 语句之间可以指定一个或多个 Transact-SQL 语句。CATCH 块必须紧跟 TRY 块。CATCH 块以 BEGIN CATCH 语句开头,以 END CATCH 语句结尾。在 Transact-SQL 中,每个 TRY 块仅与一个 CATCH 块相关联。

错误函数

TRY...CATCH 使用错误函数来捕获错误信息。
    ERROR_NUMBER() 返回错误号。
    ERROR_MESSAGE() 返回错误消息的完整文本。此文本包括为任何可替换参数(如长度、对象名称或时间)提供的值。
    ERROR_SEVERITY() 返回错误严重性。
    ERROR_STATE() 返回错误状态号。
    ERROR_LINE() 返回导致错误的例程中的行号。
    ERROR_PROCEDURE() 返回出现错误的存储过程或触发器的名称。

示例

--错误消息存储过程
if (object_id('proc_error_info') is not null)
    drop procedure proc_error_info
go
create proc proc_error_info
as
    select
        error_number() '错误编号',
        error_message() '错误消息',
        error_severity() '严重性',
        error_state() '状态好',
        error_line() '错误行号',
        error_procedure() '错误对象(存储过程或触发器)名称';
go

示例:用异常处理错误信息

--简单try catch示例
begin try
    select 1 / 0;
end try
begin catch
    exec proc_error_info; --调用错误消息存储过程
end catch
go

示例:异常能处理的错误信息

--
--简单try catch示例,无法处理错误
begin try
    select * * from student;
end try
begin catch
    exec proc_error_info;
end catch
go
--
--简单try catch示例,不处理错误(不存在的表对象)
begin try
    select * from st;
end try
begin catch
    exec proc_error_info;
end catch
go
--
--异常处理,能处理存储过程(触发器)中(不存在表对象)的错误信息
if (object_id('proc_select') is not null)
    drop procedure proc_select
go
create proc proc_select
as
    select * from st;
go
begin try
    exec proc_select;
end try
begin catch
    exec proc_error_info;
end catch
go

异常不能处理编译期的错误,如语法错误。以及重编译造成部分名称对象得不到正确解析的时候所出现的错误。

示例:无法提交的事务

--创建临时用表
if (object_id('temp_tab', 'u') is not null)
    drop table temp_tab
go
create table temp_tab(
    id int primary key identity(100000, 1),
    name varchar(200)
)
go
begin try
    begin tran;
    --没有createTime字段
    alter table temp_tab drop column createTime;
    commit tran;
end try
begin catch
    exec proc_error_info;--显示异常信息
    if (xact_state() = -1)
    begin
        print '会话具有活动事务,但出现了致使事务被归类为无法提交的事务的错误。'
            + '会话无法提交事务或回滚到保存点;它只能请求完全回滚事务。'
            + '会话在回滚事务之前无法执行任何写操作。会话在回滚事务之前只能执行读操作。'
            + '事务回滚之后,会话便可执行读写操作并可开始新的事务。';
    end
    else if (xact_state() = 0)
    begin
        print '会话没有活动事务。';
    end
    else if (xact_state() = 1)
    begin
        print '会话具有活动事务。会话可以执行任何操作,包括写入数据和提交事务。';
    end
end catch
go

示例:处理异常日志信息

--
---异常、错误信息表
if (object_id('errorLog', 'U') is not null)
    drop table errorLog
go
create table errorLog(
    errorLogID int primary key identity(100, 1),    --ErrorLog 行的主键。
    errorTime datetime default getDate(),            --发生错误的日期和时间。
    userName sysname default current_user,            --执行发生错误的批处理的用户。
    errorNumber int,                                --发生的错误的错误号。
    errorSeverity int,                                --发生的错误的严重性。
    errorState int,                                    --发生的错误的状态号。
    errorProcedure nvarchar(126),                    --发生错误的存储过程或触发器的名称。
    errorLine int,                                    --发生错误的行号。
    errorMessage nvarchar(4000)
)
go
--
--存储过程:添加异常日志信息
if (object_id('proc_add_exception_log', 'p') is not null)
    drop proc proc_add_exception_log
go
create proc proc_add_exception_log(@logId int = 0 output)
as
begin
    set nocount on;
    set @logId = 0;
    begin try
        if (error_number() is null)
            return;
        if (xact_state() = -1)
        begin
            print '会话具有活动事务,但出现了致使事务被归类为无法提交的事务的错误。'
                + '会话无法提交事务或回滚到保存点;它只能请求完全回滚事务。'
                + '会话在回滚事务之前无法执行任何写操作。会话在回滚事务之前只能执行读操作。'
                + '事务回滚之后,会话便可执行读写操作并可开始新的事务。';
        end
        else if (xact_state() = 0)
        begin
            print '会话没有活动事务。';
        end
        else if (xact_state() = 1)
        begin
            print '会话具有活动事务。会话可以执行任何操作,包括写入数据和提交事务。';
        end
        --添加日志信息
        insert into errorLog values(getDate(),
            current_user, error_number(),
            error_severity(), error_state(),
            error_procedure(),
            error_line(), error_message());
        --设置自增值
        select @logId = @@identity;
    end try
    begin catch
        print '添加异常日志信息出现错误';
        exec proc_error_info;--显示错误信息
        return -1;
    end catch
end
go
--
---处理异常信息示例
declare @id int;
begin try
    begin tran;
    --删除带有外键的记录信息
    delete classes where id = 1;
    commit tran;
end try
begin catch
    exec proc_error_info;--显示错误信息
    if (xact_state() <> 0)
    begin
        rollback tran;
    end
    exec proc_add_exception_log @id output
end catch
select * from errorLog where errorLogID = @id;
go

游标

游标可以对一个select的结果集进行处理,或是不需要全部处理,就会返回一个对记录集进行处理之后的结果。

1、游标实际上是一种能从多条数据记录的结果集中每次提取一条记录的机制。

游标可以完成:

  • 允许定位到结果集中的特定行
  • 从结果集的当前位置检索一行或多行数据
  • 支持对结果集中当前位置的进行修改

由于游标是将记录集进行一条条的操作,所以这样给服务器增加负担,一般在操作复杂的结果集的情况下,才使用游标。SQL Server 2005有三种游标:T-SQL游标、API游标、客户端游标。

2、游标的基本操作

游标的基本操作有定义游标、打开游标、循环读取游标、关闭游标、删除游标。

A、 定义游标

declare cursor_name    --游标名称
cursor [local | global]    --全局、局部
[forward only | scroll]    --游标滚动方式
[read_only | scroll_locks | optimistic]    --读取方式
for select_statements                    --查询语句
[for update | of column_name ...]        --修改字段

参数:

forward only | scroll:前一个参数,游标只能向后移动;后一个参数,游标可以随意移动

read_only:只读游标

scroll_locks:游标锁定,游标在读取时,数据库会将该记录锁定,以便游标完成对记录的操作

optimistic:该参数不会锁定游标;此时,如果记录被读入游标后,对游标进行更新或删除不会超过

B、 打开游标

open cursor_name;

游标打开后,可以使用全局变量@@cursor_rows显示读取记录条数

C、 检索游标

fetch cursor_name;

检索方式如下:

fetch first; 读取第一行

fetch next; 读取下一行

fetch prior; 读取上一行

fetch last; 读取最后一行

fetch absolute n; 读取某一行

如果n为正整数,则读取第n条记录

如果n为负数,则倒数提取第n条记录

如果n为,则不读取任何记录

fetch pelative n

如果n为正整数,则读取上次读取记录之后第n条记录

如果n为负数,则读取上次读取记录之前第n条记录

如果n为,则读取上次读取的记录

D、 关闭游标

close cursor_name;

E、 删除游标

deallocate cursor_name;

3、游标操作示例

--创建一个游标
declare cursor_stu cursor scroll for
    select id, name, age from student;
--打开游标
open cursor_stu;
--存储读取的值
declare @id int,
        @name nvarchar(20),
        @age varchar(20);
--读取第一条记录
fetch first from cursor_stu into @id, @name, @age;
--循环读取游标记录
print '读取的数据如下:';
--全局变量
while (@@fetch_status = 0)
begin
    print '编号:' + convert(char(5), @id) + ', 名称:' + @name + ', 类型:' + @age;
    --继续读取下一条记录
    fetch next from cursor_stu into @id, @name, @age;
end
--关闭游标
close area_cursor;
--删除游标
--deallocate area_cursor;

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 详解SQL Server中的事务与锁问题

    一  概述 在数据库方面,对于非DBA的程序员来说,事务与锁是一大难点,针对该难点,本篇文章试图采用图文的方式来与大家一起探讨. "浅谈SQL Server 事务与锁"这个专题共分两篇,上篇主讲事务及事务一致性问题,并简略的提及一下锁的种类和锁的控制级别. 下篇主讲SQL Server中的锁机制,锁控制级别和死锁的若干问题. 二   事务 1   何为事务 预览众多书籍,对于事务的定义,不同文献不同作者对其虽有细微差别却大致统一,我们将其抽象概括为: 事务:指封装且执行单个或多个操作的

  • sqlserver 游标的简单示例

    Declare @Id varchar(20) Declare @Name varchar(20) Declare Cur Cursor For select substring(id,0,7) as id,name from temp1 Open Cur Fetch next From Cur Into @Id,@Name While @@fetch_status=0 Begin Update temp Set [c3]=@Name where [id] like @Id+'%' Fetch

  • SqlServer异常处理常用步骤

    SQL Server常见的问题主要是SQL问题造成,常见的主要是CPU过高和阻塞. 一.CPU过高的问题 1.查询系统动态视图查询执行时间长的sql语句 WITH ProcessCTE(blocked) AS ( SELECT spid FROM sys.sysprocesses WHERE cpu>500 ) SELECT distinct a.* FROM ( SELECT TEXT,AA.* FROM sys.sysprocesses AA CROSS APPLY sys.dm_exec_

  • Sql Server中的事务介绍

    1.什么是事务:事务是一个不可分割的工作逻辑单元,在数据库系统上执行并发操作时事务是做为最小的控制单元来使用的. 他包含的所有数据库操作命令作为一个整体一起向系提交或撤消,这一组数据库操作命令要么都执行,要么都不执行. 事务是一个不可分割的工作逻辑单元 2.事务的分类.   按事务的启动与执行方式,可以将事务分为3类:   ①显示事务 :也称之为用户定义或用户指定的事务,即可以显式地定义启动和结束的事务.分布式事务属于显示事务   ②自动提交事务:默认事务管理模式.如果一个语句成功地完成,则提交

  • SQL Server异常代码处理的深入讲解

    前言 SQL Server使用TRY...CATCH 结构实现TSQL语句的错误处理,TRY命令负责监控语句执行的情况,如果有TSQL语句发生异常,并且严重级别(Severity Level)大于10,并且小于20,那么CATCH命令会捕获到异常的错误. BEGIN TRY { sql_statement | statement_block } END TRY BEGIN CATCH [ { sql_statement | statement_block } ] END CATCH 数据库开发工

  • SQL Server游标的介绍与使用

    游标概念 数据库操作中我们常常会遇到这样情况,即从某一结果集中逐一地读取一条记录.那么如何解决这种问题呢?游标为我们提供了一种极为优秀的解决方案. 游标(cursor)是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果. 每个游标区都有一个名字.用户可以用SQL语句逐一从游标中获取记录,并赋给主变量,交由主语言进一步处理.游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制. 游标总是与一条SQL 查询语句

  • SQL Server 事务,异常和游标详解

    目录 事务 1. 事务的特点 2. 事务的模式 3. 事务处理 4. 事务的示例 异常 错误函数 示例:用异常处理错误信息 示例:异常能处理的错误信息 示例:无法提交的事务 示例:处理异常日志信息 游标 1.游标实际上是一种能从多条数据记录的结果集中每次提取一条记录的机制. 2.游标的基本操作 3.游标操作示例 总结 事务 在数据库中有时候需要把多个步骤的指令当作一个整体来运行,这个整体要么全部成功,要么全部失败,这就需要用到事务. 1. 事务的特点 事务有若干条T-SQL指令组成,并且所有的指

  • SQL Server 2012 FileTable 新特性详解

    FileTable是基于FILESTREAM的一个特性.有以下一些功能: •一行表示一个文件或者目录. •每行包含以下信息: • •file_Stream流数据,stream_id标示符(GUID). •用户表示和维护文件及目录层次关系的path_locator和parent_path_locator •有10个文件属性 •支持对文件和文档的全文搜索和语义搜索的类型列. •filetable强制执行某些系统定义的约束和触发器来维护命名空间的语义 •针对非事务访问时,SQL Server配置FIL

  • sql server 交集,差集的用法详解

    概述 为什么使用集合运算: 在集合运算中比联接查询和EXISTS/NOT EXISTS更方便. 并集运算(UNION) 并集:两个集合的并集是一个包含集合A和B中所有元素的集合. 在T-SQL中.UNION集合运算可以将两个输入查询的结果组合成一个结果集.需要注意的是:如果一个行在任何一个输入集合中出现,它也会在UNION运算的结果中出现.T-SQL支持以下两种选项: (1)UNION ALL:不会删除重复行 -- union allselect country, region, city fr

  • SQL Server批量插入数据案例详解

    在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题.下面介绍SQL Server支持的两种批量数据插入方法:Bulk和表值参数(Table-Valued Parameters),高效插入数据. 新建数据库: --Create DataBase create database BulkTestDB; go use BulkTestDB; go --Create Table Create tab

  • SQL Server实现全文搜索查询详解

    目录 一.概述 二.全文搜索查询 三.将全文搜索查询与 LIKE 谓词进行比较 四.全文搜索体系结构 4.1.SQL Server 进程 4.2.过滤器守护程序主机进程 五.全文搜索处理 5.1.全文索引过程 5.2.全文查询流程 六.全文索引体系结构 6.1.全文索引结构 6.2.全文索引片段 6.3.全文索引和常规 SQL Server 索引之间的差异 总结 一.概述 全文索引在表中包括一个或多个基于字符的列.这些列可以具有以下任何数据类型:char.varchar.nchar.nvarch

  • SQL Server的行级安全性详解

    目录 一.前言 二.描述 三.权限 四.安全说明:侧信道攻击 五.跨功能兼容性 六.示例 一.前言 行级别安全性使您能够使用组成员身份或执行上下文来控制对数据库表中行的访问. 行级别安全性 (RLS) 简化了应用程序中的安全性设计和编码.RLS 可帮助您对数据行访问实施限制.例如,您可以确保工作人员仅访问与其部门相关的数据行.另一个示例是将客户的数据访问限制为仅与其公司相关的数据. 访问限制逻辑位于数据库层中,而不是远离另一个应用程序层中的数据.每次尝试从任何层访问数据时,数据库系统都会应用访问

  • SQL Server时间戳功能与用法详解

    本文实例讲述了SQL Server时间戳功能与用法.分享给大家供大家参考,具体如下: 一直对时间戳这个概念比较模糊,相信有很多朋友也都会误认为:时间戳是一个时间字段,每次增加数据时,填入当前的时间值.其实这误导了很多朋友. 1.基本概念 时间戳:数据库中自动生成的唯一二进制数字,与时间和日期无关的, 通常用作给表行加版本戳的机制.存储大小为 8个字节. 每个数据库都有一个计数器,当对数据库中包含 timestamp 列的表执行插入或更新操作时,该计数器值就会增加.该计数器是数据库时间戳.这 可以

  • sql server 自定义分割月功能详解及实现代码

    在最近的项目开发过程中,遇到了Sql server自动分割月的功能需求,这里在网上整理下资料. 1.为何出现自定义分割月的需求 今天梳理一个平台的所有函数时,发现了一个自定义分割月函数,也就是指定分割月的开始日索引值(可以从1-31闭区间内的任何一个值)来获取指定日期所对应的分割月数值.这个函数当时是为了解决业务部门获取非标准月(标准月就是从每个月的第一天到最后一天组成一个完成的标准月份)的统计汇总数据的.例如:如果指定分割月的开始日索引值为5则表示某个月的5号到下个月的4号之间作为一个完整的分

  • Python操作Sql Server 2008数据库的方法详解

    本文实例讲述了Python操作Sql Server 2008数据库的方法.分享给大家供大家参考,具体如下: 最近由于公司的一个项目需要,需要使用Sql Server 2008数据库,开发语言使用Python,并基于windows平台上的Wing IDE4.0进行. 之前并未使用过Sql Server数据库,这次也当作一次练手,并把这次数据库前期开发过程中遇到的一些问题进行记录. 一.关于pyodbc库和pymssql库的选择 在使用python语言进行开发之前,需要确定使用哪种第三方的数据库操作

  • SQL Server中T-SQL 数据类型转换详解

    常用的转换函数是 cast 和 convert,用于把表达式得出的值的类型转换成另一个数据类型,如果转换失败,该函数抛出错误,导致整个事务回滚.在SQL Server 2012版本中,新增两个容错的转换函数:try_cast 和 try_convert,如果转换操作失败,该函数返回null,不会导致整个事务失败,事务继续执行下去. 注意:对于SQL Server显式定义的不合法转换,try_cast 和 try_convert 会失败,抛出错误信息:Explicit conversion fro

随机推荐