数据库-事务处理
(1)定义:
事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。所以事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。
事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。是恢复和并发控制的基本单位。
(2)事务是DBMS的基本单位,是构成单一逻辑工作单元的操作集合
(3)事务的四个基本特征(ACID):
① Atomic(原子性):一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
② Consistency(一致性):事务完成时,数据必须处于一致状态,数据的完整性约束没有被破坏,事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
③ Isolation(隔离性):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
④ Durability(持久性):也称永久性(permanence)事务结束后持续性,指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响,事务处理的结果必须能够得到固化。
(4)事务的SQL操作语句:
① 开始事务:begin TRANSACTION;
② 提交事务:commit TRANSACTION;
③ 回滚事务:rollback TRANSACTION;
(5)事务的并发问题:
一个数据库可能拥有多个访问客户端,这些客户端都可以并发方式访问数据库。数据库中的相同数据可能同时被多个事务访问,如果没有采取必要的隔离措施,就会导致各种并发问题,破坏数据的完整性。事务的并发问题可以归结为5类,包括3类数据读问题(脏读、幻象读和不可重复读)以及2类数据更新问题(第一类丢失更新和第二类丢失更新)。
① 脏读:A事务读取B事务尚未提交的更改数据
② 不可重复读:A事务读取了B事务已经提交的数据【更改或删除】,导致两次读不一致
③ 幻想读:A事务读取了B事务【新增】的数据。
④ 第一类丢失更新:A事务撤销时,把已经提交的B事务的更新数据覆盖了
⑤ 第二类丢失更新:A事务提交时覆盖了B事务提交的数据
(6)事务日志
事务日志主要用于记录对事务的更新操作,包括增加,删除,修改。在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。 数据库是要被广大客户所共享访问的,那么在数据库操作过程中很可能出现以下几种不确定情况。
a.更新丢失:两个事务都同时更新一行数据,一个事务对数据的更新把另一个事务对数据的更新覆盖了。这是因为系统没有执行任何的锁操作,因此并发事务并没有被隔离开来。
b.脏读:一个事务读取到了另一个事务未提交的数据操作结果。这是相当危险的,因为很可能所有的操作都被回滚。
例如:
张三的工资为5000,事务A中把他的工资改为8000,但事务A尚未提交。与此同时,事务B正在读取张三的工资,读取到张三的工资为8000。随后,事务A发生异常,而回滚了事务。张三的工资又回滚为5000。最后,事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读。
c.不可重复读:(Non-repeatable Reads):一个事务对同一行数据重复读取两次,但是却得到了不同的结果。
例如:
在事务A中,读取到张三的工资为5000,操作没有完成,事务还没提交。与此同时,事务B把张三的工资改为8000,并提交了事务。随后,在事务A中,再次读取张三的工资,此时工资变为8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。
d.虚读:事务T1读取某一数据后,事务T2对其做了修改,当事务T1再次读该数据时得到与前一次不同的值。
e.幻读(Phantom Reads):事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。
例如:
目前工资为5000的员工有10人,事务A读取所有工资为5000的人数为10人。此时,事务B插入一条工资也为5000的记录。这是,事务A再次读取工资为5000的员工,记录为11人。此时产生了幻读。
解决方案
为了避免上面出现的几种情况,在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同。级别由低到高Read Uncommitted、Read Committed、Repeatable Read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。
a.未授权读取,也称为读未提交(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。
b.授权读取,也称为读提交(Read Committed):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。
c.可重复读取(Repeatable Read):禁止不可重复读取和脏读取,但是有时可能出现幻读数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。
d.序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
(7)MySQL事务控制语句
在mysql命令行的默认下,事务都是自动提交的,sql语句提交后马上会执行commit操作。因此开启一个事务必须使用begin,start transaction,或执行 set autocommit=0;
可以使用的事务控制语句:
start transction | begin // 显示的开启一个事务
commit (commit work)
rollback,rollback work