事务
第一个问题,为什么需要事务?我们先来看一个例子
USE E_Market
GO
CREATE TABLE bank--创建一张表
(
name varchar(20)NOT NULL,
mymoney money
)
GO
ALTER TABLE bank--给mymoney添加检查约束,金额必须大于等于1
ADD CONSTRAINT mymoney CHECK(mymoney>=1)
GO
INSERT INTO bank(name,mymoney) VALUES ('张三',500)
INSERT INTO bank(name,mymoney) VALUES ('李四',2500)
GO
--我们让张三给李四转账500
UPDATE bank SET mymoney=mymoney-500 WHERE name='张三'
UPDATE bank SET mymoney=mymoney+500 WHERE name='李四'
GO
这时报出一个错误,因为mymoney必须大于等于1,当张三减去500的时候,就会违反检查约束。
这时候银行转账就出现了错误,张三没减,李四却加了500.
转账是一个整体性的动作,其中一个步骤出错,其他动作也应该停止,这时我们来学习事务。
事务的概念
事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。是一系列操作,这些操作作为整体向系统提交,要么都执行,要么都不执行,事务是一个不可分割的工作逻辑单元。
例子:转账就是一个事务,当其中任何一步出现错误时,则整个转账也应该取消,各个账户中的余额也应该恢复到原状态。
特性
事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。
原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
事务的创建
开始事务:BEGIN TRANSACTION
提交事务:COMMIT TRANSACTION
回滚(撤销)事务:ROLLBACK TRANSACTION
--用事务解决银行转账的例子
BEGIN TRANSACTION --开始事务
DECLARE @error int --定义变量累积错误
SET @error=0
UPDATE bank SET mymoney=mymoney-500 WHERE name='张三'
SET @error=@error+@@ERROR--更新错误值
UPDATE bank SET mymoney=mymoney+500 WHERE name='李四'
SET @error=@error+@@ERROR
IF(@error<>0) --如果错误变量不等于0,则说明有错误发生,撤销事务
BEGIN
PRINT '交易失败,事务撤销'
ROLLBACK TRANSACTION
END
ELSE -- 否则,提交事务
BEGIN
PRINT '交易成功,写入数据库'
COMMIT TRANSACTION
END
SELECT *FROM bank --查询一下bank表,数据没改变。
事务嵌套和事物数
事务中也可以嵌套事务。
全局变量@@TRANSCOUNT记录事务数。
执行BEGIN TRANSACTION时,@@TRANSCOUNT加1.
执行 COMMIT TRANSACTION时,@@TRANSCOUNT减1.
执行ROLLBACK TRANSACTION时,@@TRANSCOUNT直接清0,所有事务全部撤销。
事务分类
显式事务:
显式事务就是可以显式地在其中定义事务的开始和结束的事务。
SET IMPLICIT_TRANSACTIONS OFF 设置显式事务模式
隐式事务:
当以隐性事务模式进行操作时,SQL Server 数据库引擎实例将在提交或回滚当前事务后自动启动新事务。无须描述事务的开始,只需提交或回滚每个事务。
SET IMPLICIT_TRANSACTIONS ON 设置显式事务模式
自动提交事务:
自动提交模式是 SQL Server 数据库引擎的默认事务管理模式。每个 Transact-SQL 语句在完成时,都被提交或回滚。如果一个语句成功地完成,则提交该语句;如果遇到错误,则回滚该语句。只要没有显式事务或隐性事务覆盖自动提交模式,与数据库引擎实例的连接就以此默认模式操作。
在 BEGIN TRANSACTION 语句启动显式事务或隐性事务设置为开启之前,与数据库引擎实例的连接一直以自动提交模式操作。当提交或回滚显式事务或关闭隐性事务模式时,连接将返回到自动提交模式。
如果设置为 ON,SET IMPLICIT_TRANSACTIONS 会将连接设置为隐式事务模式。如果设置为 OFF,则使连接恢复为自动提交事务模式。
事务执行方式
串行方式:按照顺序一个一个事务依次执行。
并发方式:所有的事务可以同时执行,和java多线程一个概念。
事务并发引起的问题
脏读,某个事务读取的数据是另一个事务正在处理的数据,而另一个事务可能会回滚,造成第一个事务读取的数据是错误的。
不可重复读:当一个事务读取某一数据后,另一事务对该数据执行了更新操作,使得第一个事务无法再次读取和前一次一样的数据。
幻读:例如第一个事务对一个表中的所有行进行修改,第二个事务是向表中插入一行数据,这时操作第一个事务的用户就会发现还有没修改的行,像发生了幻觉。
数据丢失更新:多个事务同时更新数据,导致后面的更新覆盖前面的更新,例如两个人买火车票,有一百张,第一个事务执行后为99张,第二个执行更新后还是99,就发生了错误。
解决事务并发的方案–加锁
这里我们并不过多深入,专攻数据库的可以找资料去更一步学习。