1.事务

事务在SQL Server中相当于一个工作单元,可以确保同时发生的行为与数据的有效性不发生冲突,并且维护数据的完整性。在实际应用中,多个用户在同一时刻对同一部分数据进行操作时,可能会由于一个用户的操作使其他用户的操作和数据失效。事务可以很好地解决这一点。事务总是确保数据库的完整性。

1.1.事务的ACID属性

  • 原子性(Atomicity):事务是工作单元。事务内的所有工作要不全部完成,要不全部没完成,不存在完成一部分的说法。
  • 一致性(Consistency):事务完成时,所有的数据都必须是一致的。事务结束时,所有内部数据结构都必须是正确的。
  • 隔离性(Isolation):由并发事务所做的修改必须与其他并发事务所做的修改隔离。事务识别数据时数据所处的状态,要不是另一并发事务修改前的状态,要不是另一并发事务修改后的状态,不存在中间状态。
  • 持久性(Durability):事务提交后,事务所完成的工作结果会得到永久保存。

示例1:情况如下2个代码

--语句1:
UPDATE student
SET stu_birthday='1993-02-01',
stu_native_place='山西',
stu_phone='15729810290'
WHERE stu_no='20180101'
--语句2:
UPDATE student
SET stu_birthday='1993-02-01'
WHERE stu_no='20180101'
UPDATE student
SET stu_native_place='山西'
WHERE stu_no='20180101'
UPDATE student
SET stu_phone='15729810290'
WHERE stu_no='20180101'

在语句1中,只有一个事务,对列的更新要不全部成功更新,要不全部更新失败。而语句2中,有三个事务,就算其中有某个列更新失败,也不会影响其他列的更新。

1.2.事务分类

1.2.1.系统提供的事务

系统提供的事务是指执行某些T-SQL语句时,一条语句段构成了一个事务,如ALTER TABLE,CREATE,DELETE,DROP,FETCH等。

1.2.2.用户自定义的事务

实际应用中,经常使用用户自定义的事务。自定义的方法是,以BEGIN TRANSACTION开始,以COMMIT TRANSACTION或ROLLBACK TRANSACTION结束。这两个语句之间所有语句都被视为一体。

示例2:自定义事务的应用

BEGIN TRANSACTION
INSERT INTO student(stu_no,stu_name,stu_birthday,stu_enter_score)
VALUES('20180013','贾乃亮','1993-01-20','498')
INSERT INTO student(stu_no,stu_name,stu_birthday,stu_enter_score)
VALUES('20180014','周星星','1993-07-20','532')
INSERT INTO student(stu_no,stu_name,stu_birthday,stu_enter_score)
VALUES('20180015','雨化田','错误格式数据','570')
INSERT INTO student(stu_no,stu_name,stu_birthday,stu_enter_score)
VALUES('20180016','周琪','1993-01-20','653')
INSERT INTO student(stu_no,stu_name,stu_birthday,stu_enter_score)
VALUES('20180017','陈璐','1998-01-20','599')
COMMIT TRANSACTION

在上面的事务中,第三条插入数据是错误数据,无法成功插入,执行上面的语句,发现所有插入语句都没有被执行成功。

还有一种用户自定义事务——分布式事务。如果在比较复杂的环境中,有多台服务器,为了保证服务器中数据的完整性和一致性,就必须定义一个分布式事务。举个例子,有2台服务器,一台存放库存数据,另一台存放订单数据,用户下单的逻辑是,下单前先扣除库存数据,再下单。如果没有分布式事务,容易出现扣除库存数量,单下单却没成功,造成两个数据库数据不一致的情况。

1.3.管理事务

主要使用以下4条语句管理事务:BEGIN TRANSACTION,COMMIT TRANSACTION,ROLLBACK TRANSACTION和SAVE TRANSACTION。此外还有2个全局变量可以用在事务处理语句中:@@ERROR和@@TRANCOUNT。

BEGIN TRANSACTION,COMMIT TRANSACTION,ROLLBACK TRANSACTION不多说了。

1.3.1.SAVE TRANSACTION

允许部分地提交一个事务,同时仍能回退这个事务的剩余部分。

示例3:BEGIN TRANSACTION,COMMIT TRANSACTION,ROLLBACK TRANSACTION和SAVE TRANSACTION的结合使用

执行下列语句

BEGIN TRANSACTION changed
INSERT INTO student(stu_no,stu_name,stu_sex,stu_enter_score)
VALUES('20180014','谭晶','男','533')
SAVE TRANSACTION saveinsert--设置保存事务点saveinsert
UPDATE student
SET stu_sex='错误数据'
WHERE stu_no='20180014'
ROLLBACK TRANSACTION saveinsert--回滚到保存事务点saveinsert
COMMIT TRANSACTION changed

上述代码完成了一个这样的功能:设置一个事务,事务名changed,该事务的作用是向student表中插入一条记录并更新该记录的stu_sex字段。如果更新失败,则回滚到插入操作,即保证不管更新是否成功,插入操作都能成功。

1.3.2.@@TRANCOUNT变量和@@ERROR变量

@@TRANCOUNT变量报告当前嵌套事务为第几层嵌套,每个BEGIN TRANSACTION都能使@@TRANCOUNT加一,@@ERROR变量用来保存任何一条T-SQL语句的最新错误号。

示例4:对示例3中代码加上对@@TRANCOUNT和@@ERROR变量的访问

执行下列语句

BEGIN TRANSACTION changed
SELECT @@TRANCOUNT AS trancount
INSERT INTO student(stu_no,stu_name,stu_sex,stu_enter_score)
VALUES('20180016','陈甜甜','女','661')
SAVE TRANSACTION saveinsert--设置保存事务点saveinsert
UPDATE student
SET stu_sex='错误数据'
WHERE stu_no='20180016'
SELECT @@ERROR AS error
ROLLBACK TRANSACTION saveinsert--回滚到保存事务点saveinsert
COMMIT TRANSACTION changed
GO

结果如图所示



示例5:对@@TRANCOUNT变量的理解

执行下列语句

BEGIN TRANSACTION changed1
SELECT @@TRANCOUNT AS trancount
INSERT INTO class(class_id,class_name,enter_score_level)
VALUES('07','TEST','TEST')
BEGIN TRANSACTION changed2
INSERT INTO class(class_id,class_name,enter_score_level)
VALUES('08','TEST','TEST')
BEGIN TRANSACTION changed3
SELECT @@TRANCOUNT AS trancount
INSERT INTO class(class_id,class_name,enter_score_level)
VALUES('09','TEST','TEST')
COMMIT TRANSACTION changed3
COMMIT TRANSACTION changed2
COMMIT TRANSACTION changed1

我在changed1和changed3中对@@TRANCOUNT变量进行了访问,结果如图所示



每个BEGIN TRANSACTION都使@@TRANCOUNT加一。

1.4.SQL Server本地事务支持

应用程序主要通过设置事务开始时间和事务结束时间来管理事务。这可以通过函数或者应用程序接口(API)实现。默认情况下,事务按连接级别进行处理,使用API函数或者SQL语句,可以将事务作为显式,隐式和自动提交事务来处理。

1.4.1.自动提交事务模式

自动提交事务模式是SQL Server默认的事务管理模式,每个SQL语句都是一个事务,在完成时都会被提交或回滚。在自动提交事务模式下,当遇到的错误是编译时错误,会回滚整个批处理,当遇到的错误是运行时错误,不会回滚整个批处理,而是执行部分语句并提交。

示例6:遇到编译时错误和运行时错误时,事务处理方式是不同的

执行下列语句

--编译时错误代码
USE test
GO
CREATE TABLE T1(
id INT NOT NULL,
name VARCHAR(20),
age INT,
CONSTRAINT pk_id PRIMARY KEY(id)
)
GO
INSERT INTO T1(id,name,age)VALUES
('1001','宋佳佳','26')
INSERT INTO T1(id,name,age)VALUES
('1002','陈琦','23')
INSERT INTO T1(id,name,age)VALUE
('1003','卢哲','27')--语法错误,回滚整个批处理
GO
SELECT * FROM T1

结果可以看到,T1表虽然被创建了,但是三条数据都没有插入成功。可见编译时错误会回滚整个批处理。

删除T1表后执行下列语句

--运行时错误代码
USE test
GO
CREATE TABLE T1(
id INT NOT NULL,
name VARCHAR(20),
age INT,
CONSTRAINT pk_id PRIMARY KEY(id)
)
GO
INSERT INTO T1(id,name,age)VALUES
('1001','宋佳佳','26')
INSERT INTO T1(id,name,age)VALUES
('1002','陈琦','23')
INSERT INTO T1(id,name,age)VALUES
('1001','卢哲','27')--主键重复错误,仅该语句不执行
GO
SELECT * FROM T1

结果如图所示



仅错误的INSERT语句不执行,而整个批处理并没有回滚。可见运行时错误不会导致整个批处理被回滚,仅仅只是中断执行。

1.4.2.显式事务模式

有明显使用BEGIN TRANSACTION语句定义一个事务的就是显式事务模式。示例2,3,4,5都是显式事务模式。

1.4.3.隐式事务模式

隐式事务模式是一种连接选项,在该选项下每个连接执行的SQL语句都被视为单独的事务。当连接以隐式事务模式进行操作时,SQL Server将在事务提交或事务回滚后自动开始新事务。隐式事务模式无需BEGIN TRANSACTION这种语句来进行定义。

1.4.3.1.通过SET IMPLICIT_TRANSACTIONS ON语句设置隐式事务模式

显式事务模式模式会在有大量DDL和DML语句执行时自动开始,并一直保持到用户明确提交为止。也就是说,如果设置了隐式事务模式,而SQL语句中又有事务没有明确提交,即使用COMMIT TRANSACTION语句提交,那么用户断开连接,或者关闭数据库时,系统会询问有未提交的事务,是否提交,如果选择否,那么未提交的事务将会被回滚,下次连接时就不存在了。

示例7:执行下列语句

SET IMPLICIT_TRANSACTIONS ON
GO USE test
CREATE TABLE T1(
id INT NOT NULL,
name VARCHAR(20),
age INT,
CONSTRAINT pk_id PRIMARY KEY(id)
)
INSERT INTO T1(id,name,age)VALUES
('1001','宋佳佳','26')
COMMIT TRANSACTION
INSERT INTO T1(id,name,age)VALUES
('1002','陈琦','23')
INSERT INTO T1(id,name,age)VALUES
('1003','卢哲','27')
SELECT * FROM T1

结果如图所示



然后断开连接,出现如下提示



如果选择否的话,再次连接成功后SELECT T1表,结果如图所示



会发现1002和1003的记录都被回滚了,那是因为在插入的时候,这两条语句的事务没有COMMIT,只有第一条插入语句被提交了。这就是隐式事务模式。

1.4.3.2.调用API函数来设置隐式事务模式

用来设置隐式事务模式的API机制是ODBC和OLE DB(不能理解,不多说了)

1.4.4.批范围的事务

该事务只适用于多个活动的结果集。在MARS会话中启动的SQL显式或隐式事务,将变成批范围事务,当批处理完成时,如果批范围事务还没有被提交或回滚,SQL Server将自动对其进行回滚。

1.5.隔离级别

当多个线程都开启事务来操作数据库中的数据时,数据库要能进行隔离操作,以确保各个线程获取数据的准确性。如果没有隔离操作,会出现以下几种情况:

  • 脏读:一个事务处理过程里读取了另一个未提交的事务中的数据。

例如:A转100块钱给B,SQL语句如下

UPDATE acount
SET cash=cash+100
WHERE name='B'--此时A通知B
UPDATE acount
SET cash=cash-100
WHERE name='A'

执行完第一条语句时,A通知B,让B确认是否到账,B确认钱到账(此时发生了脏读),而后无论第二条SQL语句是否执行,只要事务没有提交,所有操作都将回滚,B第二次查看时发现钱没有到账。

  • 不可重复读:一个事务范围内多次查询某个数据,返回不同的值,这是因为该数据被另一个事务修改并提交了。脏读和不可重复读的区别在于,脏读是读取了另一个事务还未提交的数据,不可重复都是读取了反复读取了前一个事务提交了的数据
  • 幻读:比如事务T1将表中某一列数据从1修改成2,同时T2事务插入一条数据,该列值仍然是1,那么用户查询时就会发现该表还有1列数据为1,未被T1事务修改。

1.5.1.四种隔离级别

  • 未提交读(READ UNCOMMITTED):事务隔离的最低级别,可执行未提交读和脏读,任何情况都无法保证
  • 提交读(READ COMMITTED):在读取数据时控制共享锁,避免脏读,但无法避免不可重复读和幻读。它是SQL Server 2008的默认值。
  • 可重复读(REPEATABLE READ):锁定查询过程中所有数据,防止用户更新数据,避免了脏读和不可重复读的发生,无法避免幻读。
  • 可串行读(SERIALZABLE):在数据集上放置一个范围锁,防止其他用户在事务完成之前更新数据或插入行,是事务隔离的最大限制级别,避免了脏读,不可重复读和幻读的发生。

事务隔离级别越高,越能保证数据的一致性和完整性。

1.5.2.设置事务隔离级别

默认情况下,SQL Server 2008的事务隔离级别为提交读。可通过SET TRANSACTION ISOLATION LEVEL来设置事务隔离级别。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

1.6.分布式事务

对多个数据库中的数据进行修改的事务,是分布式事务。这些数据库可以是本地数据库,也可以是其他链接服务器上的数据库。

分布式事务由一个分布式事务协调程序(DTC)来控制,若想使用分布式事务,必须先启动该服务。在分布式事务中用COMMIT TRANSACTION提交事务,数据库会自动调用一个两步提交协议:1.通知每个数据库核实它们能够提交该事务并保留资源。2.当每个相关数据库通知SQL Server 2008可以随时提交该事务后,SQL Server 2008通知相关数据库提交该事务。如果有一个数据库不能成功提交该事务,则SQL Server 2008会通知所有相关数据库回滚该事务。

1.7.高级事务主题

  • 嵌套事务:显式事务可以嵌套在存储过程中
  • 事务保存点:提供了一种可以部分回滚事务的机制
  • 绑定会话:有利于在一个服务器上的多个会话之间的协调操作,允许一个或多个会话共享事务和锁,并且可以使用同一个数据,不会有锁的冲突

1.8.管理长时间运行的事务

1.8.1.查看长时间运行的事务

执行下列语句

SELECT * FROM sys.dm_tran_database_transactions

结果如图所示

1.8.2.停止事务

停止事务可能必须运行KILL语句,使用该语句时要小心,特别是在运行重要的进程时。

《SQL Server 2008从入门到精通》--20180724的更多相关文章

  1. 《SQL Server 2008从入门到精通》--20180717

    目录 1.触发器 1.1.DDL触发器 1.2.DML触发器 1.3.创建触发器 1.3.1.创建DML触发器 1.3.2.创建DDL触发器 1.3.3.嵌套触发器 1.3.4.递归触发器 1.4.管 ...

  2. 《SQL Server 2008从入门到精通》--20180716

    1.锁 当多个用户同时对同一个数据进行修改时会产生并发问题,使用事务就可以解决这个问题.但是为了防止其他用户修改另一个还没完成的事务中的数据,就需要在事务中用到锁. SQL Server 2008提供 ...

  3. 《SQL Server 2008从入门到精通》--20180710

    目录 1.使用Transact-SQL语言编程 1.1.数据定义语言DDL 1.2.数据操纵语言DML 1.3.数据控制语言DCL 1.4.Transact-SQL语言基础 2.运算符 2.1.算数运 ...

  4. 《SQL Server 2008从入门到精通》--20180704

    XML查询技术 XML文档以一个纯文本的形式存在,主要用于数据存储.不但方便用户读取和使用,而且使修改和维护变得更容易. XML数据类型 XML是SQL Server中内置的数据类型,可用于SQL语句 ...

  5. 《SQL Server 2008从入门到精通》--20180703

    SELECT操作多表数据 关于连接的问题,在<SQL必知必会>学习笔记中已经讲到过,但是没有掌握完全,所以再学一下. JOIN连接 首先我们先来看一下最简单的连接.Products表和Ve ...

  6. 《SQL Server 2008从入门到精通》--20180628

    数据库基本概念:区.页.行 区:SQL Server中管理空间的基本单位.一个区大小为64KB,是八个物理上连续的页.SQL Server中每MB有16个区.一旦一个区被存储满,SQL Server将 ...

  7. 《SQL Server 2008从入门到精通》20180627

    数据库范式理论 范式理论是为了建立冗余较小结构合理的数据库所遵循的规则.关系数据库中的关系必须满足不同的范式.目前关系数据库有六种范式:第一范式(1NF).第二范式(2NF).第三范式(3NF).BC ...

  8. 《SQL Server 2008从入门到精通》--20180723

    目录 1.架构 1.1.创建架构并在架构中创建表 1.2.删除架构 1.3.修改表的架构 2.视图 2.1.新建视图 2.2.使用视图修改数据 2.3.删除视图 3.索引 3.1.聚集索引 3.2.非 ...

  9. 《SQL Server 2008从入门到精通》--20180629

    约束 主关键字约束(Primary Key Constraint) 用来指定表中的一列或几列组合的值在表中具有唯一性.建立主键的目的是让外键来引用. Primary Key的创建方式 在创建表时创建P ...

随机推荐

  1. Element ui tree结合Vue使用遇到的一些问题(一)

    下图是一个后台管理系统,展示的是角色列表 当我点击编辑的时候,弹出一个模态框,如下图 功能需求:点击编辑按钮,弹出模态框,选择权限那块,默认选中当前角色拥有的权限. 问题:第一次点击编辑按钮时,不会选 ...

  2. 解决docker镜像无法下载的问题

    从daocloud.io中找到了获取镜像的方式,在镜像仓库中可以找到镜像的地址,其他镜像地址可以以此类推: # docker pull daocloud.io/library/centos:lates ...

  3. Log4j按级别输出日志到不同文件配置

    1.自定义LogFileAppender类,继承DailyRollingFileAppender,实现Log4j按级别输出日志到不同文件. package com.liying.mango.commo ...

  4. C/C++求职宝典21个重点笔记(常考笔试面试点)

    这是我之前准备找工作时看<C/C++求职宝典>一书做的笔记,都是一些笔试面试中常考的重点难点问题,但比较基础,适合初学者看. 1. char c = '\72'; 中的\72代表一个字符, ...

  5. redis-小用

    1.redis之flushall.flushdb‘尴尬’操作恢复 redis是基于内存的一种高效数据库,在内存中高效但是不安全,重启和断电都会导致数据丢失.所以就需要用到数据的持久化,redis有两种 ...

  6. RocketMQ专题1:入门

    RocketMQ入门 源码和应用下载 ​ 这里以RocketMQ的4.3.0版本为例,本地环境为windows10,jdk1.8, maven3.2.1. 源码下载地址: http://mirrors ...

  7. 传统项目转前端工程化——路由跳转时出现浏览器锁死和白屏【该死的同步ajax】

    [一开始我想到是该死的同步ajax,但我没验证,把他忽略了] 在探索前端工程化vue-cli做spa时,从搜索结果页跳转商品详情页时,因为详情页有很多ajax请求,并且都用的同步请求,就会导致请求时浏 ...

  8. 在ASP.NET MVC应用程序中随机获取一个字符串

    在开发ASP.NET MVC应用程序时,有可能需要一个随机字符串,作为密码或是验证码等. 如果你需要的是SQL版本,可以参考<密码需要带特殊字符(二)>http://www.cnblogs ...

  9. docker 第一次学习(一)--安装以及相关命令

    转自:https://www.jianshu.com/p/c69a2a3b4c7a https://docs.docker.com/ http://www.dockerinfo.net/documen ...

  10. [javascript] 看知乎学习js事件触发过程

    红色箭头代表捕获阶段 蓝色代表目标阶段 绿色代表冒泡阶段 调用元素对象的addEventListener()方法,参数:事件,回调函数,是否捕获(true代表捕获阶段,false代表冒泡阶段,ie浏览 ...