SQL Server 事务、异常和游标
建议先阅读存储过程:SQL Server 存储过程
Ø 事务
在数据库中有时候需要把多个步骤的指令当作一个整体来运行,这个整体要么全部成功,要么全部失败,这就需要用到事务。
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 catchif (@tran_error > 0) begin --执行出错,回滚事务 rollback tran; print '转账失败,取消交易'; endelse begin --没有异常,提交事务 commit tran; print '转账成功'; endgo
Ø 异常
在程序中,有时候完成一些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_infogocreate proc proc_error_infoas select error_number() '错误编号', error_message() '错误消息', error_severity() '严重性', error_state() '状态好', error_line() '错误行号', error_procedure() '错误对象(存储过程或触发器)名称';go
# 示例:用异常处理错误信息
--简单try catch示例begin try select 1 / 0;end trybegin catch exec proc_error_info; --调用错误消息存储过程end catchgo
# 示例:异常能处理的错误信息
----简单try catch示例,无法处理错误begin try select * * from student;end trybegin catch exec proc_error_info;end catchgo----简单try catch示例,不处理错误(不存在的表对象)begin try select * from st;end trybegin catch exec proc_error_info;end catchgo----异常处理,能处理存储过程(触发器)中(不存在表对象)的错误信息if (object_id('proc_select') is not null) drop procedure proc_selectgocreate proc proc_selectas select * from st;gobegin try exec proc_select;end trybegin catch exec proc_error_info;end catchgo
异常不能处理编译期的错误,如语法错误。以及重编译造成部分名称对象得不到正确解析的时候所出现的错误。
# 示例:无法提交的事务
--创建临时用表if (object_id('temp_tab', 'u') is not null) drop table temp_tabgocreate 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 trybegin 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 '会话具有活动事务。会话可以执行任何操作,包括写入数据和提交事务。'; endend catchgo
# 示例:处理异常日志信息
-----异常、错误信息表if (object_id('errorLog', 'U') is not null) drop table errorLoggocreate 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_loggocreate proc proc_add_exception_log(@logId int = 0 output)asbegin 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 catchendgo-----处理异常信息示例declare @id int;begin try begin tran; --删除带有外键的记录信息 delete classes where id = 1; commit tran;end trybegin catch exec proc_error_info;--显示错误信息 if (xact_state() <> 0) begin rollback tran; end exec proc_add_exception_log @id outputend catchselect * 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;
转载于:https://www.cnblogs.com/dogxuefeng/p/4612742.html
SQL Server 事务、异常和游标相关推荐
- SQL Server事务回滚对自增键的影响
SQL Server事务回滚时是删除原先插入导致的自增值,也就是回滚之前你你插入一条数据导致自增键加1,回滚之后还是加1的状态 --如果获取当前操作最后插入的identity列的值: select @ ...
- SQL Server事务日志采访问题
In this article, we will discuss some important SQL Server Transaction Log interview questions that ...
- sql server 事务_SQL Server事务概述
sql server 事务 In general, a Transaction is a single unit of work consists of multiple related tasks ...
- 如何处理SQL Server事务复制中的大事务操作
如何处理SQL Server事务复制中的大事务操作 事务复制的工作机制 事务复制是由 SQL Server 快照代理.日志读取器代理和分发代理实现的.快照代理准备快照文件(其中包含了已发布表和数据库对 ...
- SQL Server事务的隔离级别
SQL Server事务的隔离级别 ########## 数据库中数据的一致性 ########## 针对并发事务出现的数据不一致性,提出了4个级别的解决方法: 隔离级别 第一类丢失更新 脏读 ...
- SQL Server 事务日志
https://docs.microsoft.com/en-us/sql/relational-databases/logs/the-transaction-log-sql-server?view=s ...
- Sql Server事务日志
本文导读:SQL Server中的数据库都是由一或多个数据文件以及一或多个事务日志文件组成的.SQL Server事务日志主要是用来记录所有事务对数据库所做的修改,SQL SERVER利用事务日志来确 ...
- 了解SQL Server事务日志备份和完整备份的日志序列号
This article explores the SQL Server Transaction log backups and log sequence number (LSN) in combin ...
- 使用SQL Server事务复制将SQL Server数据库迁移到Azure SQL数据库
In this guide, we'll discuss more about migrating a SQL Server database to Azure SQL Database using ...
- 如何使用损坏或删除SQL Server事务日志文件重建数据库
This is the last article, but not the least one, in the SQL Server Transaction Log series. In this s ...
最新文章
- javascript(js)的小数点乘法除法问题
- 通过案例练习掌握SSH 的整合
- 深度学习难,这本书让你轻松学深度学习
- BSTestRunner——一个丑在路上的python unnitest HTML报告生成Runner
- Vivado 随笔(6) Timing Summary 相关讨论(一)
- 面试题39:二叉树的深度、判断二叉树是不是平衡
- 关于python安装lxml插件的问题
- 腾讯云大数据产品中心总经理刘煜宏:企业全域数据体系建设(附完整PPT)
- NILMTK——因子隐马尔可夫之隐马尔可夫
- 使用拓扑数据分析理解卷积神经网络模型的工作过程
- 2020年国内电影总票房突破100亿元
- oracle之三手工不完全恢复
- 画出传输门、三态门、开路门_谷仓门优缺点有哪些?安装效果绝对出彩
- 在PHP中2中特殊数据类型是,@PHP中的数据类型(2)
- Atitit mybatis返回多个数据集总结 目录 1.1. 配置handleResult接受,但是只有第一个select语句的结果	1 2. 配置resultMap ok	1 2.1. 调
- C语言程序设计谭浩强第五版复习梳理3
- win7序列号(可激活所有版本)
- 基于DPABI和SPM12的任务态fMRI分析笔记2——统计检验
- Macos IntelliJ maven web项目tomcat8 启动时报错Cannot run program apache-tomcat-8/bin/catalina.sh解决方法
- Facebook借足球影响力推广直播:与俱乐部和球星合作分成
热门文章
- java 策略模式会员_七:策略模式(不同等级会员打折算法)
- mysql 导入一个数据库_mysql导入一个数据库
- 对于150kHz导航信号放大接收模块测试实验
- 第十五届全国大学生智能汽车竞赛各分赛区成绩汇总
- 基于Manim针对FT教学过程的一种可行性设计
- 基于i.MX RT电磁智能车AI算法的一些讨论
- tello通信_【我的项目666】+通讯管理(5)modbus-RTU主机
- python在线编辑器编译excel_python在线编译器的简单原理及简单实现代码
- java 显式锁_Java 实现一个自己的显式锁Lock(有超时功能)
- python操作html5日期控件_python、js 时间日期模块time