事务
一、定义
全称(Transaction Control Language)翻译成中文 事务控制语言,事务是访问并可能更新数据库各种数据项的一个程序执行单元,
是并发控制的单元,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。通过事务,sql 能将逻辑相关的一组操作绑定在一起,以便服务器 保持数据的完整性。
二 为什么要事务
设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作:
- 更新客户所购商品的库存信息
- 保存客户付款信息--可能包括与银行系统的交互
- 生成订单并且保存到数据库中
- 更新用户相关信息,例如购物数量等等
正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新。但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常、该顾客银行帐户存款不足等,都将导致交易失败。一旦交易失败,数据库中所有信息都必须保持交易前的状态不变,比如最后一步更新用户信息时失败而导致交易失败,那么必须保证这笔失败的交易不影响数据库的状态--库存信息没有被更新、用户也没有付款,订单也没有生成。否则,数据库的信息将会一片混乱而不可预测。
数据库事务正是用来保证这种情况下交易的平稳性和可预测性的技术
默认情况下会自动提交,也就是说每个SQL语句都是在其完成时提交到数据库。
事务只针对DDL操作
三、事务的特性(ACID)
1、案例
- A账户向B账号汇钱的例子来说明如何通过数据库事务保证数据的准确性和完整性
1、从A账号中把余额读出来(500)
2、对A账号做减法操作(500-100)
3、把结果写回A账号中(400)
4、从B账号中把余额读出来(500
5、对B账号做加法操作(500+100)
6、把结果写回B账号中(600)
2、原子性(atomicity)
- 概念
事务是数据库的逻辑工作单位,而且是必须是原子工作单位,对于其数据修改,要么全部执行,要么全部不执行。 - 说明
保证1-6所有过程要么都执行,要么都不执行。一旦在执行某一步骤的过程中发生问题,就需要执行回滚操作。 假如执行到第五步的时候,B账户突然不可用(比如被注销),那么之前的所有操作都应该回滚到执行事务之前的状态
3、一致性(consistency)
- 概念
事务在完成时,必须是所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。 - 说明
在转账之前,A和B的账户中共有500+500=1000元钱。在转账之后,A和B的账户中共有400+600=1000元。也就是说,数据的状态在执行该事务操作之后从一个状态改变到了另外一个状态。同时一致性还能保证账户余额不会变成负数等
4、隔离性(isolation)
- 概念
也称为独立性,是指并行事务的修改必须与其他并行事务的修改相互独立。一个事务处理数据,要么是其他事务执行之前的状态,要么是其他事务执行之后的状态,但不能处理其他正在处理的数据。
企业级的数据库每一秒钟都可能应付成千上万的并发访问,因而带来了并发控制的问题。 - 说明
在A向B转账的整个过程中,只要事务还没有提交(commit),查询A账户和B账户的时候,两个账户里面的钱的数量都不会有变化。
如果在A给B转账的同时,有另外一个事务执行了C给B转账的操作,那么当两个事务都结束的时候,B账户里面的钱应该是A转给B的钱加上C转给B的钱再加上自己原有的钱
5、持久性(durability)
- 概念
一个事务一旦提交,事物的操作便永久性的保存在DB中。即使此时再执行回滚操作也不能撤消所做的更改 - 说明
一旦转账成功(事务提交),两个账户的里面的钱就会真的发生变化(会把数据写入数据库做持久化保存)
四、基本操作
1、事务常用的语句
语句 | |
---|---|
BEGIN或START TRANSACTION | 显式地开启一个事务; |
COMMIT | 也可以使用COMMIT WORK,不过二者是等价的。COMMIT会提交事务,并使已对数据库进行的所有修改成为永久性的; |
ROLLBACK | 有可以使用ROLLBACK WORK,回滚会结束用户的事务,并撤销正在进行的所有未提交的修改; |
SAVEPOINT identifier | SAVEPOINT允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT; |
RELEASE SAVEPOINT identifier | 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常; |
ROLLBACK TO identifier; | 把事务回滚到标记点; |
SET TRANSACTION | 用来设置事务的隔离级别。InnoDB存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。 |
2、MYSQL 事务处理主要有两种方法:
- 用 BEGIN, ROLLBACK, COMMIT来实现
- BEGIN 开始一个事务
- ROLLBACK 事务回滚
- COMMIT事务提交
- 直接用 SET 来改变 MySQL 的自动提交模式
- SET AUTOCOMMIT=0 禁止自动提交
- SET AUTOCOMMIT=1 开启自动提交
3 、案例
- 前期准备工作
-- 创建银行账户表 create table account( aid int primary key auto_increment comment '注解', cardno varchar(16) not null unique comment '银行卡号', name varchar(20) not null comment '姓名', money decimal(10,2) default 0.0 comment '金额' ) -- 插入数据 insert into account (cardno,name,money) values ('1', '小明', 500), ('2', '娇娇', 500);
- 第一步 开始事务
-- 告诉系统以下所有操作,不要直接写入数据库,先存到事务日志。 BEGIN
- 第二步 减少账户的余额
update account set money = money - 1000 where cardno =1
- 第三步 增加账户的余额
update account set money = money + 1000 where cardno = 2;
- 第四步 提交事务
commit;
- 第五步 或者回滚
rollback
五、事务隔离 - 并发控制
3.1、并发控制
数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性
3.2、不考虑事务的隔离性,会出现什么问题?
- 脏读:一个事务读取到另一个事务的未提交数据
- 不可重复读:两次读取的数据不一致(强调update)
- 虚读(幻读):两次读取的数据不一致(强调insert)
- 丢失更新:两个事务对同一条记录进行操作,后提交的事务,将先提交的事务的修改覆盖了
3.3、四种隔离级别
- Read uncommitted:最低级别,以上情况均无法保证。(读未提交)
- Read committed:可避免脏读情况发生(读已提交)
- Repeatable read:可避免脏读、不可重复读情况的发生。(可重复读)不可以避免虚读
- Serializable:可避免脏读、不可重复读、虚读情况的发生。(序列化,不仅有read、write锁还有range lock范围锁(没有where锁全表,有where锁where范围);对一张表的所有增删改操作必须顺序执行,性能最差)
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read uncommitted | √ | √ | √ |
Read committed | × | √ | √ |
Repeatable read | × | × | √ |
Serializable | × | × | × |
1、Read uncommitted(读未提交)
- 举个栗子
又到月底了,小明的老婆要准备给小明发生活费了,小明的老婆给小明打了550块,但该事务并没有提交,而此时小明正好在查余额,发现是550块,高兴的差点蹦了起来.天有不测风云,突然小明的老婆发现多打了50块,于是回滚事务,修改金额,然后将事务提交,最后小明空欢喜异常。
-
示例图
image
2、Read committed (读提交,不可重复读)
- 举个栗子
某个夜黑风高的夜晚,小明丰富的夜生活开始了,小明拿着工资卡去消费,pos机读取卡的信息的时候有500, 而此时小红也正好在网上转账,把小明工资卡的500元转到另一账户,并小明之前提交了事务,当小明扣款时, 系统检查到小明的工资卡已经没有钱,扣款失败,小明十分纳闷,明明卡里有钱,为什么会说余额不足, 出现上述情况,即我们所说的不可重复读,两个并发的事务,“事务1:小明消费”、“事务2:小红网上转账”,事务1事先读取了数据, 事务2紧接了更新了数据,并提交了事务,而事务1再次读取该数据时,数据已经发生了改变, 当隔离级别设置为Read committed时,避免了脏读,但是可能会造成不可重复读
-
示意图
image
- 备注
Sql Server ,Oracle的默认级别
3、Repeatable read 幻读
- 举例说明
小红最近发现小明总是很晚回家并且经常不接电话,于是小红开始查小明当月信用卡的总消费金额, 消费金额为50,而小明此时正好在收银台买单,消费1000元,即新增了一条1000元的消费记录,并提交了事务, 随后小红将小明当月信用卡消费的明细打印了出来,却发现消费总额为1050元,小红很诧异,以为出现了幻觉
-
示例图
image
- 备注
MySQL的默认隔离级别
4、Serializable 序列化
- 说明
最高级别:防止上述3种情况,事务串行执行,慎用
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决不读脏,可重复读,不可幻读。
简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争
5、更新丢失问题
- 说明
由于RDBMS都有锁机制,所以在并发事务中不存在更新丢失问题 1>加锁阶段:在该阶段可以进行加锁操作。在对任何数据进行读操作之前要申请并获得S锁,在进行写操作之前要申请 2>并获得X锁。 加锁不成功,则事务进入等待状态,直到加锁成功才继续执行。 解锁阶段:当事务释放了一个封锁以后,事务进入解锁阶段,在该阶段只能进行解锁操作不能再进行加锁操作
六、事务的原则
1、说明
尽可能使事务保持简短很重要,当事务启动后,数据库管理系统 (DBMS) 必须在事务结束之前保留很多资源、以保证事务的正确安全执行。 特别是在大量并发的系统中, 保持事务简短以减少并发 资源锁定争夺,将显得更为重要。
2、原则
- 事务处理,禁止与用户交互,在事务开始前完成用户输入。
- 在浏览数据时,尽量不要打开事务
- 尽可能使事务保持简短。
- 考虑为只读查询使用快照隔离,以减少阻塞。
- 灵活地使用更低的事务隔离级别。
- 在事务中尽量使访问的数据量最小。
网友评论