https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BA%8B%E5%8A%A1/9744607?fr=aladdin
编辑
数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。
中文名
数据库事务
外文名
(Database Transaction)
实 质
一系列操作
要 求
必须满足所谓的ACID属性
编辑
设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作:
一、更新客户所购商品的库存信息
二、保存客户付款信息--可能包括与银行系统的交互
三、生成订单并且保存到数据库中
四、更新用户相关信息,例如购物数量等等
正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新。但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常、该顾客银行帐户存款不足等,都将导致交易失败。一旦交易失败,数据库中所有信息都必须保持交易前的状态不变,比如最后一步更新用户信息时失败而导致交易失败,那么必须保证这笔失败的交易不影响数据库的状态--库存信息没有被更新、用户也没有付款,订单也没有生成。否则,数据库的信息将会一片混乱而不可预测。
数据库事务正是用来保证这种情况下交易的平稳性和可预测性的技术。
编辑
(Atomic)(Atomicity)
事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。如果系统只执行这些操作的一个子集,则可能会破坏事务的总体目标。原子性消除了系统处理操作子集的可能性。
(Consistent)(Consistency)
事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。某些维护一致性的责任由应用程序开发人员承担,他们必须确保应用程序已强制所有已知的完整性约束。例如,当开发用于转帐的应用程序时,应避免在转帐过程中任意移动小数点。
(Insulation)(Isolation)
由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。这称为隔离性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。当事务可序列化时将获得最高的隔离级别。在此级别上,从一组可并行执行的事务获得的结果与通过连续运行每个事务所获得的结果相同。由于高度隔离会限制可并行执行的事务数,所以一些应用程序降低隔离级别以换取更大的吞吐量。
(Duration)(Durability)
事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。
编辑
企业级的数据库管理系统(DBMS)都有责任提供一种保证事务的物理完整性的机制。就常用的SQL Server2000系统而言,它具备锁定设备隔离事务、记录设备保证事务持久性等机制。因此,我们不必关心数据库事务的物理完整性,而应该关注在什么情况下使用数据库事务、事务对性能的影响,如何使用事务等等。
作为大型的企业级数据库,SQL Server2000对事务提供了很好的支持。我们可以使用SQL语句来定义、提交以及回滚一个事务。
编辑
事务有三种模型:
1.隐式事务是指每一条数据操作语句都自动地成为一个事务,事务的开始是隐式的,事务的结束有明确的
标记。
2.显式事务是指有显式的开始和结束标记的事务,每个事务都有显式的开始和结束标记。
3.自动事务是系统自动默认的,开始和结束不用标记。
并发控制
1. 数据库系统一个明显的特点是多个用户共享数据库资源,尤其是多个用户可以同时存取相同数据。
串行控制:如果事务是顺序执行的,即一个事务完成之后,再开始另一个事务
并行控制:如果DBMS可以同时接受多个事务,并且这些事务在时间上可以重叠执行。
2.并发控制概述
事务是并发控制的基本单位,保证事务ACID的特性是事务处理的重要任务,而并发操作有可能会破坏其ACID特性。
DBMS并发控制机制的责任:
对并发操作进行正确调度,保证事务的隔离性更一般,确保数据库的一致性。
如果没有锁定且多个用户同时访问一个数据库,则当他们的事务同时使用相同的数据时可能会发生问题。由于并发操作带来的数据不一致性包括:丢失数据修改、读”脏”数据(脏读)、不可重复读、产生幽灵数据。
(1)丢失数据修改
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。如上例。
再例如,两个编辑人员制作了同一文档的电子复本。每个编辑人员独立地更改其复本,然后保存更改后的复本,这样就覆盖了原始文档。最后保存其更改复本的编辑人员覆盖了第一个编辑人员所做的更改。如果在第一个编辑人员完成之后第二个编辑人员才能进行更改,则可以避免该问题。
(2)读“脏”数据(脏读)
读“脏”数据是指事务T1修改某一数据,并将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被除撤消,而此时T1把已修改过的数据又恢复原值,T2读到的数据与数据库的数据不一致,则T2读到的数据就为“脏”数据,即不正确的数据。
例如:一个编辑人员正在更改电子文档。在更改过程中,另一个编辑人员复制了该文档(该复本包含到目前为止所做的全部更改)并将其分发给预期的用户。此后,第一个编辑人员认为所做的更改是错误的,于是删除了所做的编辑并保存了文档。分发给用户的文档包含不再存在的编辑内容,并且这些编辑内容应认为从未存在过。如果在第一个编辑人员确定最终更改前任何人都不能读取更改的文档,则可以避免该问题。
( 3)不可重复读
指事务T1读取数据后,事务T2执行更新操作,使T1无法读取前一次结果。不可重复读包括三种情况:
事务T1读取某一数据后,T2对其做了修改,当T1再次读该数据后,得到与前一不同的值。
(4)产生幽灵数据
按一定条件从数据库中读取了某些记录后,T2删除了其中部分记录,当T1再次按相同条件读取数据时,发现某些记录消失
T1按一定条件从数据库中删除某些数据记录后,T2插入了一些记录,当T1再次按相同条件读取数据时,发现多了一些记录。
词条标签:
软件 , 科技术语 , 科学 , 技术
https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BA%8B%E5%8A%A1/9744607?fr=aladdin
https://blog.csdn.net/u013007900/article/details/77927723
原
2017年09月11日 00:22:32 SuPhoebe 阅读数:13733更多
所属专栏: 高级数据库
版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/u013007900/article/details/77927723
事务(txn)是一系列在共享数据库上执行的行为,以达到更高层次更复杂逻辑的功能。事务是DBMS中最基础的单位,事务不可分割。
ACID,是指在可靠数据库管理系统(DBMS)中,事务(transaction)所应该具有的四个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
原子性是指事务是一个不可再分割的工作单位,事务中的操作要么都发生,要么都不发生。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
假设A要给B转钱,在事务中的扣款和加款两条语句,要么都执行,要么就都不执行。否则如果只执行了扣款语句,就提交了,此时突然断电,A账号已经发生了扣款,B账号却没收到加款,在生活中就会引起纠纷。
一致性是指事务使得系统从一个一致的状态转换到另一个一致状态。这是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。
对银行转帐事务,不管事务成功还是失败,应该保证事务结束后ACCOUNT表中A和B的存款总额始终为2000元。如果一个人扣100元,一个人得50元,就破坏了一致性。
事务的一致性决定了一个系统设计和实现的复杂度。事务可以不同程度的一致性:
- 强一致性:读操作可以立即读到提交的更新操作。
- 弱一致性:提交的更新操作,不一定立即会被读操作读到,此种情况会存在一个不一致窗口,指的是读操作可以读到最新值的一段时间。
- 最终一致性:是弱一致性的特例。事务更新一份数据,最终一致性保证在没有其他事务更新同样的值的话,最终所有的事务都会读到之前事务更新的最新值。如果没有错误发生,不一致窗口的大小依赖于:通信延迟,系统负载等。
- 其他一致性变体还有:
- 单调一致性:如果一个进程已经读到一个值,那么后续不会读到更早的值。
- 会话一致性:保证客户端和服务器交互的会话过程中,读操作可以读到更新操作后的最新值。
多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。
这指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。
并行时可能出现的问题:
- 脏读:事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。
- 不可重复读:在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。
- 幻读:在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。
不同的隔离级别:
- Read Uncommitted:最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
- Read Committed:只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。
- Repeated Read:在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。
- Serialization:事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。
隔离级别 | 脏读 | 丢失更新 | 不可重复读 | 幻读 | 并发模型 | 更新冲突检测 |
---|---|---|---|---|---|---|
未提交读:Read Uncommited | √ | √ | √ | √ | 悲观 | ×× |
已提交读:Read commited | ×× | √ | √ | √ | 悲观 | ×× |
可重复读:Repeatable Read | ×× | ×× | ×× | √ | 悲观 | ×× |
可串行读:Serializable | ×× | ×× | ×× | ×× | 悲观 | ×× |
持久性,意味着在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
即使出现了任何事故比如断电等,事务一旦提交,则持久化保存在数据库中。
计算的是本地的变量,不会被DBMS看到,所以不会在之后过多讨论;
使用调用或语句级别的接口访问DBMS,一般开始于Begin,接着是一系列操作,最后以COMMIT或者ROLLBACK结束。
特点
一旦回滚,则将整个事务的所有操作进行回滚,所有在没有COMMIT之前的操作全部丢失
改进
存档点(savepoint)
当事务检测到数据库需要回滚它之前做的部分操作的时候,事务可以直接自己取消自己之前的操作,也可以使用ROLLBACK机制去undo这些操作。
当我们把savepoint2给释放了,操作做出的改变还在,但是我们已经不能够通过savepoint回到那个位置了;而且savepoint3依赖于savepoint2,在释放后者的同时,也会把前者给释放了,因此我们也无法回到savepoint3。
savepoint将事务变成一系列的每一个都可以单独回滚的行为。
嵌套事务是一套有层次的操作,子事务的结果要依赖于它父亲事务的操作。
多个事务顺序执行,一个事务COMMIT之后,另一个事务马上BEGIN,没有事务可以两个事务之间对数据进行修改。
和savepoint不同的地方在于:
批量更新问题
批量更新(bulk update)本身就是一个天然事务,如果一旦失败则全部回滚。
虽然链式事务模型解决了这个问题,但是它要求应用自己去解决维护数据库状态、解决失败操作这些问题。因为DBMS没有办法将整个事务回滚。
一种特殊类型的事务,用于将之前事务的操作结果进行消除。这种消除只能是逻辑层面的,而不是物理层面的。
SAGE事务
由两个链式事务构成,分别是是T1,T2,…,TnT1,T2,…,Tn,和对应事务的补偿事务C1,C2,…,CnC1,C2,…,Cn。
事务的提交顺序只能是两种:
特意解释一句,这种事务在设计到更加复杂的更新的时候就(应该)难以进行维护。同时,这种事务是不能通过DBMS实现的,而是在应用层面上进行维护的。
谈谈数据库的ACID
收藏
分享
https://blog.csdn.net/u013007900/article/details/77927723
https://blog.csdn.net/dilixinxixitong2009/article/details/80256732
原
2018年07月31日 11:18:42 2009gis 阅读数:82
在开始编写文章前,有几个问题需要思考一下:
事务是一个工作的逻辑单元,这个单元必须是全部运行或者全部取消,不能接受中间状态。在事务中所有的 SQL 语句必须成功完成。如果 SQL 语句中的任何一个失败,那么整个事务必须回滚到原始的数据库状态,这个状态也就是该事务开始之前的状态。一个成功事务是将数据库从一个一致性状态修改到另一个一致性状态。在数据库的一致性状态里,所有数据的完整性必须满足。
每个单独的事务必须具有原子性、一致性、排他性和持久性。有时把这些性质称为 ACID。此外,当运行多个事物时,DBMS 必须安排事务同时运行。每个事务的运行调度必须具有可串行性的性质。
由于其本身的性质,单用户数据库系统自动确保可串行性和数据库的排他性,因为仅一个事务在一个时刻被运行时。原子性、一致性和事务的持久性必须由单用户 DBMS 来保证(甚至单用户 DBMS 必须从错误中恢复,这些错误包括中断、断点、不正当的应用运行)。
多用户数据库通常受多个同时存在的事务支配。因此,多用户 DBMS 必须运用管理手段,以确保可串行性和事务的排他性(还有原子性和持久性),以保证数据库的一致性和完整性,例如,如果多个同时存在的事务运行相同的数据集,并且在第一个事务完成之前,第二个事务更新了数据库。此时,违背了排他性,并且数据库也不一致的。DBMS 必须通过使用并发控制技术来管理事务,以避免这样不符合要求的情况。
美国国家标准学会制定了标准(ANSI),这个标准管理 SQL 数据库事务。事务支持有两个 SQL 语句提供:COMMIT(提交)和 ROLLBACK(回滚)。ANSI 要求事务顺序最终由用户和应用程序来设定,顺序必须支持所有随后的 SQL 语句,直到如下 4 个事件之一发生:
事务日记
DBMS 用事务日记来跟踪所有更新数据库的事务。DBMS 使用存储在日记中的信息来恢复命令,ROLLBACK 语句、程序中不正常中断或者系统错误(比如网路错误或磁盘损坏)都会触发恢复命令。一些 RDBMS 使用事务日记,把数据库恢复到当前的一致性状态。当服务器发生错误时,Oracle 自动回滚到未提交事务,并且回滚前面已提交但未写到物理数据库中的事务。这个行为要求事务的正确性,并且这是任何 DBMS 的典型情况。
当 DBMS 运行修改数据库的事务时,它总是自动更新事务日记。事务日记存储如下信息:
1、事务开始记录;
2、每个事务组件(SQL 语句):
3、事务的结束(COMMIT);
尽管使用事务日记增加 DBMS 的处理开销,但是能够恢复已毁坏的数据库,是物有所值的。
当两个或两个以上的并发事务同时运行时,可能发生严重的问题。数据库事务包括很多数据库 I/O 操作,这些操作涉及把数据库从一个一致性状态转到另一个一致性状态。如果事务更新了多个表/行,那么数据库总是在事务运行期间,有过暂时的不一致状态(如果事务仅包含一个更新,那么就没有暂时的不一致性状态)。暂时的不一致状态之所以存在,是因为计算机有序地运行操作。在这个有序的过程中,事务的排他性阻止他们访问其他事务还没释放的数据。此时,调度器的工作非常重要,它使用多核处理器,可以在同一时间运行多个操作。如果两个事务同时运行并且它们同时访问同一数据,将会发生什么呢?
在事务中的操作是随机运行的,只要两个事务 T1 和 T2 访问的是不相关的数据,就不会发生冲突,而且运行的顺序不会影响最后的结果。但是,如果事务要对相关(相同)数据进行操作,冲突可能发生在事务内部以及运行的顺序中,对另一个可能产生不满意的结果。因此,怎么确定的顺序,谁决定这个顺序?值得庆幸的是,DBMS 可以使用内置调度器来处理这种复杂的任务。
调度器是一种特殊的 DBMS 过程,它在并发事务的运行过程中创建操作的运行顺序。调度器使数据库的操作交替运行,以便保证事务的可串行化和排他性。调度器根据事务在并发控制算法中的行为(如锁或时间戳方法),确定合理的顺序。但是,并不是所有的事务都是可串行化的,理解这一点很重要。DBMS 确定哪些事务是可串行化和交替运行的。通常,DBMS 根据先来先服务的原则,先运行那些不可串行化的事务。调度器的主要工作是生成一个事务操作的顺序安排。可串行化调度是一种事务操作的调度,在这个调度中,事务交替运行的结果与事务顺序运行的结果相同。
调度器可以提高计算机的中央处理器和存储系统的效率。如果不安排事务的运行顺序,那么所有事务都按照先进先出服务的原则。这样的问题是,当 CPU 等待一个 READ 或者 WRITE 操作完成时,浪费了处理时间,从而浪费了 CPU 的时间。简而言之,在多用户 DBMS 环境中,先进先服务调度往往产生不可接受的响应时间。因此,需要其他一些调度方法来提高整体系统的效率。此外,为了确保两个事务同时更新同一数据,调度有助于数据的隔离。数据库操作中的 READ 与 WRITE 或者 WRITE 与 WRITE 都可能产生冲突。在并发事务中有几种方法来调度冲突操作的运行。这方法是锁、时间戳、优化等。
在多用户数据库系统中,多个事务同时运行的协作。并发控制的目的是为了确保在多用户数据库环境中,事务的可串行化。并发控制是很重要的,因为在同一个数据库,事务同时运行会产生数据的完整性和一致性问题。3 个主要的问题是更新丢失、未提交数据和不一致检索。
锁保证了当前事务对数据的独立性。换句话说,当事务 T1 正在使用一个数据时,事务 T2 不能访问这个数据。事务在获得对数据访问之前,先获得锁。只有在这个事务完成并释放锁之后,其他事务才可以对这个数据加锁。
大部分的多用户 DBMS 自动启动和实施锁程序。锁管理器管理所有的锁信息,并且负责分配和监督所有事务使用的锁。
锁粒度表示的锁使用级别。锁可有如下级别决定:数据库级、表级、页级、行级、甚至字段(属性)级。
1、数据库级
在数据库级锁中,当事务 T1 在运行时,为了防止事务 T2 使用数据库中的表,锁住整个数据库。锁的级别对成批的处理很好,但是对多用户 DBMS 则是不合理的。试想一下,在新的事务申请数据库之前,如果有成百上千的事务必须等待前面事务完成,那么数据库的访问有多么慢?下图说明数据库级锁。注意,由于是数据库级锁,即使是要访问数据库中的 T1 和 T2 也不能同时访问这个数据库。
2、表级锁
在表级锁中,当事务 T1 正在使用表时,为了防止事务 T2 访问该表的任何一行,锁住整个表。如果一个事务需要访问多个表,那么需要锁住每个表。但是只要访问的是不同表,那么两个事务是可以访问同一个数据库的。
当多个事务等待同一个表时,因为表级锁比数据库级锁限制更少,所以会引起堵塞。当不同的事务需要访问不同的表时,也就是说,当事务不会相互影响时,锁导致延迟,这样的话是很令人厌烦的。因此,表级锁对多用户的 DBMS 不适合。下图说明表级锁的作用。注意,在下图中,即使事务 T1 和事务 T2 使用不同的行,也同时不能访问同一表,T2 必须等 T1 释放表。
3、页级锁
在页级锁中,DBMS 将锁住这个磁盘页。磁盘页或者页相当于磁盘块,是直接从磁盘寻址的。页有固定的大小,如 4k、8k、16k。例如仅想把 73 字节写到 4K 的页里,则必须把整个 4K 页从磁盘中读出,然后在内存中更新,最后写会磁盘。一个表中可以存放许多页,一个页中可以包含一个或多个表中的行。下图所示的是一个页级锁例子。注意,当锁住的是不同磁盘页时,事务 T1 和 T2 才可以访问同一表。如果 T2 需要使用 T1 锁住的页中的某些行时,T2 必须等 T1 释放该页。
4、行级锁
行级锁比前面讨论的锁的严格性更低。DBMS 允许并发事务访问同一表中的不同行,即使这些行在同一页中也是如此。尽管行级锁提高了数据的可用性,但是它的管理成本却很高,因为数据库表可能含有冲突事务。当应用程序在同一页中需要更多个锁时,现代的 DBMS 会自动地把行级锁提升为页级锁。如下图,即使行请求是在同一页中,两个事务也可以同时运行。如果 T2 和 T1 同时请求同一行,T2 必须等待。
5、字段级锁
只要并发事务同时请求的是同一行的不同字段,字段级锁就允许并发事务去访问该行。尽管字段级锁产生更多灵活的多用户数据访问,但是它仅在 DBMS 中运行,因为它将使得计算机的负担极高。
锁有各种级别,DBMS 可以使用不同锁类型:二元锁、共享锁/排他锁。
1、二元锁
二元锁仅有两种状态:加锁(1)或者解锁(0)。如果一个对象——可能是一个数据库、表、页或行——被一个事务锁住,其他事务不可以使用这个对象。如果一个对象没有加锁,任何事务如果使用它就可以对它进行加锁。每个数据库运行需要对被作用的对象进行加锁。基于这个规则,一个事务在运行结束之后必须解锁。因此,每个事务对要访问的每个数据项进行加锁或解锁。DBMS 自动地管理操作和安排时间,用户不需要关心数据项的加锁和解锁(每个 DBMS 有自己默认的加锁机制,如果终端用户想要覆盖这种默认机制,可以使用 LOCK TABLE 或其他 SQL 命令)。
2、共享/排他锁
“共享” 和 “排他” 表示的是锁的性质。当事务访问对象并且要修改时,对象就加排它锁。当冲突可能发生时,必须加排它锁。如果要让并发事务可以读取数据,就加共享锁。只要并发事务只读,共享锁不会产生冲突。
如果一个事务想从数据库中读数据且这个数据没有排它锁,那么就加共享锁。当一个事务想更新(写)一个数据项且没有其他事务对这个数据项加锁时,那么就加排它锁。使用共享/排他锁思想,锁有 3 个状态:解锁、共享(读)、排他(写)。
两个事务会发生冲突的条件是,其中至少有一个是 WRITE 事务,因为两个 READ 使用可以安全地同时运行,共享锁允许多个 READ 事务同时读取相同的数据项。例如,如果事务 T1 在数据项 X 上有一个共享锁,而 T2 要读取数据项 X,那么 T2 也可以获得数据项 X 上的共享锁。
如果 T2 要更新数据项 X,就要求 T2 在数据项 X 上加一个排它锁。当且仅当数据项没有其他锁时,才可以在数据项上加排它锁。因此,如果事务 T1 已经在数据项 X 上加了共享锁或排它锁,事务 T2 就不能在加排它锁了,T2 必须等待,知道 T1 提交完成。这种条件就称为互斥原则:在同一个对象上,不能有多个事务同时施加排它锁。
尽管共享锁可以使得数据访问更高效,但共享/排他锁模式增加了锁管理器的负担,因为:
尽管锁防止了严重的数据不一致性问题,但是也可以带来下面两个问题:
庆幸的是,上面两个问题都已经解决了:通过加锁协议(如两阶段加锁)来保证可串行化,也可使用死锁检查和保护技术来防止死锁的发生。
两阶段加锁
两阶段加锁定义了事务如何获得和解锁。两阶段加锁保证了可串行化,但不能阻止死锁。这两阶段是:
两阶段加锁协议有如下规则:
参考
https://www.souyunku.com/2018/07/30/mysql
收藏
分享
https://blog.csdn.net/dilixinxixitong2009/article/details/80256732
https://www.cnblogs.com/fjdingsd/p/5273008.html
本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别。
如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性:
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。
以上介绍完事务的四大特性(简称ACID),现在重点来说明下事务的隔离性,当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性,在介绍数据库提供的各种隔离级别之前,我们先看看如果不考虑事务的隔离性,会发生的几种问题:
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。例如:用户A向用户B转账100元,对应SQL命令如下
update account set money=money+100 where name=’B’; (此时A通知B)
update account set money=money - 100 where name=’A’;
当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了……
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
现在来看看MySQL数据库为我们提供的四种隔离级别:
① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。
在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。
在MySQL数据库中查看当前事务的隔离级别:
select @@tx_isolation;
在MySQL数据库中设置事务的隔离 级别:
set [glogal | session] transaction isolation level 隔离级别名称;
set tx_isolation=’隔离级别名称;’
例1:查看当前事务的隔离级别:
例2:将事务的隔离级别设置为Read uncommitted级别:
或:
记住:设置数据库的隔离级别一定要是在开启事务之前!
如果是使用JDBC对数据库的事务设置隔离级别的话,也应该是在调用Connection对象的setAutoCommit(false)方法之前。调用Connection对象的setTransactionIsolation(level)即可设置当前链接的隔离级别,至于参数level,可以使用Connection对象的字段:
在JDBC中设置隔离级别的部分代码:
后记:隔离级别的设置只对当前链接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效;对于JDBC操作数据库来说,一个Connection对象相当于一个链接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其他链接Connection对象无关。
参考博客:
http://www.zhihu.com/question/23989904
http://dev.mysql.com/doc/refman/5.6/en/set-transaction.html
http://www.cnblogs.com/xdp-gacl/p/3984001.html
好文要顶 关注我 收藏该文
fjdingsd
关注 - 54
粉丝 - 122
+加关注
79
1
« 上一篇:使用JDBC进行数据库的事务操作(2)
» 下一篇:数据库连接池
posted @ 2016-03-13 20:25 fjdingsd 阅读(355079) 评论(26) 编辑 收藏
https://www.cnblogs.com/fjdingsd/p/5273008.html