详解数据库的事务


在这里插入图片描述

事务简介

如果要执行一系列的操作,而这些操作最终是以整体的原子操作的形式完成的话,事务就是必须的。关于事务的理论中,银行转账问题是最经典的例子:当把钱从一个银行帐号转移至另外一个银行帐号的时候,这个操作要由两个步骤来完成,首先要将资金从一个银行帐号取出,然后再将其存入另一个银行帐号。如果资金已经从一个银行帐号取出了,在将资金存入另一个银行帐号之前或者进行当中发生异常情况(包括程序内部异常、服务器当机、目标帐号被冻结),如果没有事务保护就会出现源帐号中的资金已经减少了,但是目标帐号中的资金并没有增加的状况。
事务是关键业务系统开发中非常关键性的服务,对于关键性业务系统如果没有采用事务,那么这个系统可以说是不可用的。
事务简介
从严格的定义来讲“事务是形成一个逻辑工作单位的数据库操作的汇集”。通俗的说,事务(Transaction)是能以整体的原子操作形式完成的一系列操作,事务能保证一个“全有或者全无”的命题的成立,即操作或者全部成功或者全部失败,不会出现部分成功、部分失败的情况。事务以一种可靠的、简洁的方式来解决系统运行中的各种异常问题。
事务具有4个基本特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。简称ACID 特性。
1,原子性: 一个事务中所有的数据库操作,是一个不可分割的整体,这些操作要么全部执行,要么全部无效果。
2,一致性: 一个事务独立执行的结果,将保持数据库的一致性,即数据不会因事务的执行而被破坏。在事务执行过程中,可以违反一致性原则,并产生一个临时的不一致状态。
比如在转账过程中,会出现暂时的数据不一致的情况。当事务结束后,系统又回到一致的状态。不过临时的一致性不会导致问题,因为原子性会使得系统始终保持一致性。
3,隔离性:在多个事务并发执行的时候,系统应该保证与这些事务先后单独执行时的结果一样,即并发执行的任务不必关心其他事务。对于每一个事务来讲,那一刻看起来好像只有它在修改数据库一样。事务系统是通过对后台数据库数据使用同步协议来实现隔离性的。同步协议使一个事务与另外一个事务相分离。如果事务对数据进行了锁定,可以使并发的事务无法影响该数据,直到锁定解除为止。
4,持久性: 一个事务一旦完成全部操作以后,它对数据库的所有操作将永久地反映在数据库中。持久性保证了系统在操作的时候免遭破坏。持久性主要是为了解决机器故障、突然断电、硬盘损坏等问题而出现的。为了达到持久性,系统一般都保留了一份日志。一旦出现故障,就可以通过日志将数据重建。

事务隔离

假设同一个A和B两个同时并发操作数据库,A和B执行的任务如下:从数据库中读取整数N,将N随机加上10或者20,将新的N更新回数据库。这两个并发执行的实例可能发生下面的执行顺序。
(1) A从数据库中读取N,当前数据库中N=0;
(2) B从数据库中读取N,当前数据库中N=0;
(3) A将N加10,并更新入数据库,当前数据库中N=10
(4) B将N 加20,并更新入数据库,当前数据库中N=20;
可以看到由于数据库出现了交叉存取的操作,B所读取的N是过期的版本,即A在写回数据之前的版本。这样当B更新的时候,将会覆盖A的操作,这就是著名的 “更新丢失” 问题。那么应该如何避免这种情况的发生呢?
解决此类问题的方法就是为 数据库加锁,以防止多个组件读取数据,通过锁住事务所用的数据,能保证在打开锁之前,只有本事务才能访问数据。这样就避免了交叉存取的问题。这和操作系统中的PV操作原理类似。
由于锁将其他并发的事务排除在数据库更新之外,所以这会导致性能的严重下降。
为了提高性能,事务将锁分为两种类型:只读锁和写入锁。只读锁是非独占的,多个并发的事务都能获得只读锁;写入锁是独占的,任意时间只能有一个事务可以获得写入锁。

事务隔离级别

由于隔离性是通过加锁的方式获得的,而锁会降低系统的性能,所以事务提供了控制隔离程度的机制。如果使用较高的隔离级别,则事务会比较好的与其他事务相隔离,当然也会带来大量的系统开销;如果使用较低的隔离级别,则事务的隔离性会比较差,但是能获得更好的性能。
事务的隔离级别分为四种:READ_UNCOMMITED、READ_COMMITED、REPEATABLE_READ、SERIALIZABLE。 要理解这些隔离级别的差异必须首先弄清如下几个概念:脏读、不可重复读、幻影读取。
假设同一个A和B两个同时并发操作数据库,A和B执行的任务如下:从数据库中读取整数N,将N加上10,将新的N更新回数据库。这两个并发执行的实例可能发生下面的执行顺序。
(1) A从数据库中读取整数N,当前数据库中N=0;
(2) N 加上10,并将其更新到数据库中,当前数据库中N=10。然而由于A 的事务还没有提交,所以数据库更新还没有称为持久性的;
(3) B从数据库中读取整数N,当前数据库中N=10;
(4) A回滚了事务,所以N 恢复到了N=0;
(5) B将N 加上10,并将其更新到数据库中,当前数据库中N=20;
这里出现了B在A提交之前读取了A所更新的数据,由于A回滚了事务,所以数据库中出现了错误的数据20。尽管A回滚了事务,但是A更新的数据还是间接的通过B被更新到了数据库中。这种读取了未提交的数据的方法就叫脏(dirty)读问题。
当一个用户从数据库中读取数据的时候,另外一个用户修改了这条数据,所以数据发生了改变,当再次读取的时候就出现了不可重复读取问题。 比如:
(1) A从数据库中读取整数N;
(2) B以一个新的值更新N;
(3) 当A再次从数据库中读取N 的时候,会发现N 的值变了;
幻影读取指的是在两次数据库操作读取操作之间,一组新的数据会出现在数据库中。比如:
(1) A从数据库检索到了一些数据;
(2) B通过Insert语句插入了一些新数据;
(3) A再次查询的时候,新的数据就会出现;
了解了这几个概念,下面来看一下四种事务的隔离级别的区别:
1,使用READ_UNCOMMITED级别,会导致脏读问题、幻影读取问题和不可重复读取问题。在需要敏感计算任务的事务中,这样的模式是不太适合的;
2,使用READ_COMMITED级别,可以解决脏读问题,但是还会有幻影读取问题和不可重复读取问题。这种级别一般用于制作报表。这种模式是大部分系统的默认级别;
3,使用REPEATABLE_READ 级别,可以解决脏读问题和不可重复读取问题,但是会有幻影读取问题;
4,使用SERIALIZABLE 级别可以解决脏读问题、幻影读取问题和不可重复读取问题。这是最严格级别的隔离级别;
在这里插入图片描述总结:

  • 脏读:读到了其他事务还没有提交的数据。
  • 不可重复读:对某数据进行读取,发现两次读取的结果不同,也就是说没有读到相同的内容。这是因为有其他事务对这个数据同时进行了修改或删除。
  • 幻读:事务 A 根据条件查询得到了 N 条数据,但此时事务 B 更改或者增加了 M 条符合事务 A 查询条件的数据,这样当事务 A 再次进行查询的时候发现会有 N+M 条数据,产生了幻读。

事务使用

主流的DBMS都提供了启动、提交以及回滚事务的机制,也提供了指定锁粒度、隔离级别的机制,不过这些机制一般是谁DBMS的不同而不同的,请参考具体DBMS的说明文档。比如在MSSQLServer中执行一个READ_UNCOMMITED级别事务的SQL语句如下:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITED
BEGIN TRANSACTION
--具体的操作代码
COMMIT
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Apple_Web

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值