"Dry Technology" Ali wrote to the architect engineer Java database transactions

Understanding Affairs


1.1 Why do you need a database transaction

Transfer is the life of common operations, such as account transfer 100 yuan to B from A accounts. From the user perspective, this is a logical operation on a single, but in the database system, at least two steps may be accomplished:

  1. A reduction in the amount of the accounts of 100 yuan

  2. The amount of B accounts increased by 100 yuan.

"Dry Technology" Ali wrote to the architect engineer Java database transactions


The following problems may occur in this process:

  • The first step in the transfer operation is successful, the money on the account A reduction of $ 100, but the second step fails or does not perform a system crash will occur, leading to B accounts, and there is no corresponding increase 100 yuan.


  • Transfer operation took place just completed a system crash, lost transfer records before the collapse of the system restart recovery.


  • While another user B transfers to accounts due to simultaneous operation of the B accounts, leading to abnormal B account amount appear.

In order to facilitate the solution of these problems, it is necessary to introduce the concept of a database transaction.

1.2 What is a database transaction

Definition: the database transaction is a set operation to form a single logical unit of work, a typical database transaction as follows:

"Dry Technology" Ali wrote to the architect engineer Java database transactions


There are several definitions of the transaction need explain:

  • Database transaction may comprise one or more database operations, these operations constitute a logical whole.


  • These database operations constitute a logical whole, either all executed succeed or not performed.


  • All operations make up the transaction, either all have an impact on the database, or all do not have an impact, that is, regardless of whether the transaction is successful, the database is always consistent state.


  • Even more appear in the database is still valid in the presence of a fault and concurrent transactions.


1.3 How to solve the problem affairs

For example, the above transfer, transfer may be contained in all the operations related to a transaction

"Dry Technology" Ali wrote to the architect engineer Java database transactions


  1. When the database operation failure or system crash, the system can be restored to the border with the transaction, the case of reducing the amount of accounts A and B account does not increase does not occur.

  2. When multiple users simultaneously operate the database, the database transaction can be the unit of concurrency control, a plurality of transfer operations of the user account B isolated from each other.


Transaction systems to make it easier for fault recovery and concurrency control to ensure consistency of the database state.

1.4 ACID properties of the transaction and the realization of the principle of

Atomicity (Atomicity): all operations in the transaction as a whole as indivisible as atomic, either all succeed, or all fail.

Consistency (Consistency): the results of the transaction must be made to the database from one consistent state to another consistent state.

一致性状态是指:

  1. 系统的状态满足数据的完整性约束(主码,参照完整性,check约束等)

  2. 系统的状态反应数据库本应描述的现实世界的真实状态,比如转账前后两个账户的金额总和应该保持不变。

隔离性(Isolation):并发执行的事务不会相互影响,其对数据库的影响和它们串行执行时一样。

比如多个用户同时往一个账户转账,最后账户的结果应该和他们按先后次序转账的结果一样。

持久性(Durability):事务一旦提交,其对数据库的更新就是持久的。任何事务或系统故障都不会导致数据丢失。

在事务的ACID特性中,C即一致性是事务的根本追求,而对数据一致性的破坏主要来自两个方面:

  1. 事务的并发执行

  2. 事务故障或系统故障

数据库系统是通过并发控制技术和日志恢复技术来避免这种情况发生的。

并发控制技术保证了事务的隔离性,使数据库的一致性状态不会因为并发执行的操作被破坏。

日志恢复技术保证了事务的原子性,使一致性状态不会因事务或系统故障被破坏。

同时使已提交的对数据库的修改不会因系统崩溃而丢失,保证了事务的持久性。

"Dry Technology" Ali wrote to the architect engineer Java database transactions



并发异常与并发控制


2.1 常见的并发异常

在讲解并发控制技术前,先简单介绍下数据库常见的并发异常。

脏写,脏写是指事务回滚了其他事务对数据项的已提交修改,比如下面这种情况

"Dry Technology" Ali wrote to the architect engineer Java database transactions


在事务1对数据A的回滚,导致事务2对A的已提交修改也被回滚了。

丢失更新。丢失更新是指事务覆盖了其他事务对数据的已提交修改,导致这些修改好像丢失了一样。

"Dry Technology" Ali wrote to the architect engineer Java database transactions



事务1和事务2读取A的值都为10,事务2先将A加上10并提交修改,之后事务2将A减少10并提交修改,A的值最后为,导致事务2对A的修改好像丢失了一样

脏读。脏读是指一个事务读取了另一个事务未提交的数据

"Dry Technology" Ali wrote to the architect engineer Java database transactions



在事务1对A的处理过程中,事务2读取了A的值,但之后事务1回滚,导致事务2读取的A是未提交的脏数据。

不可重复读,指一个事务对同一数据的读取结果前后不一致。

脏读和不可重复读的区别在于:前者读取的是事务未提交的脏数据,后者读取的是事务已经提交的数据,只不过因为数据被其他事务修改过导致前后两次读取的结果不一样

比如下面这种情况

"Dry Technology" Ali wrote to the architect engineer Java database transactions


由于事务2对A的已提交修改,事务1前后两次读取的结果不一致。

幻读。幻读是指事务读取某个范围的数据时,因为其他事务的操作导致前后两次读取的结果不一致。

幻读和不可重复读的区别在于,不可重复读是针对确定的某一行数据而言,而幻读是针对不确定的多行数据。

因而幻读通常出现在带有查询条件的范围查询中,比如下面这种情况:

"Dry Technology" Ali wrote to the architect engineer Java database transactions



事务1查询A<5的数据,由于事务2插入了一条A=4的数据,导致事务1两次查询得到的结果不一样

2.2 事务的隔离级别

事务具有隔离性,理论上来说事务之间的执行不应该相互产生影响,其对数据库的影响应该和它们串行执行时一样。

然而完全的隔离性会导致系统并发性能很低,降低对资源的利用率,因而实际上对隔离性的要求会有所放宽,这也会一定程度造成对数据库一致性要求降低

SQL标准为事务定义了不同的隔离级别,从低到高依次是

  1. 读未提交(READ UNCOMMITTED)

  2. 读已提交(READ COMMITTED)

  3. 可重复读(REPEATABLE READ)

  4. 串行化(SERIALIZABLE)


事务的隔离级别越低,可能出现的并发异常越多,但是通常而言系统能提供的并发能力越强。

不同的隔离级别与可能的并发异常的对应情况如下表所示

有一点需要强调,这种对应关系只是理论上的,对于特定的数据库实现不一定准确

比如mysql的Innodb存储引擎通过Next-Key Locking技术在可重复读级别就消除了幻读的可能。

"Dry Technology" Ali wrote to the architect engineer Java database transactions


所有事务隔离级别都不允许出现脏写,而串行化可以避免所有可能出现的并发异常,但是会极大的降低系统的并发处理能力。

2.3 事务隔离性的实现—常见的并发控制技术

并发控制技术是实现事务隔离性以及不同隔离级别的关键,实现方式有很多。按照其对可能冲突的操作采取的不同策略可以分为乐观并发控制和悲观并发控制两大类。

  • 乐观并发控制:对于并发执行可能冲突的操作,假定其不会真的冲突,允许并发执行,直到真正发生冲突时才去解决冲突,比如让事务回滚。

  • 悲观并发控制:对于并发执行可能冲突的操作,假定其必定发生冲突,通过让事务等待(锁)或者中止(时间戳排序)的方式使并行的操作串行执行。


2.3.1 基于封锁的并发控制

核心思想:对于并发可能冲突的操作,比如读-写,写-读,写-写,通过锁使它们互斥执行。

锁通常分为共享锁和排他锁两种类型

  • 共享锁(S):事务T对数据A加共享锁,其他事务只能对A加共享锁但不能加排他锁。

  • 排他锁(X):事务T对数据A加排他锁,其他事务对A既不能加共享锁也不能加排他锁

基于锁的并发控制流程:

  • 事务根据自己对数据项进行的操作类型申请相应的锁(读申请共享锁,写申请排他锁)

  • 申请锁的请求被发送给锁管理器。锁管理器根据当前数据项是否已经有锁以及申请的和持有的锁是否冲突决定是否为该请求授予锁。

  • 若锁被授予,则申请锁的事务可以继续执行;若被拒绝,则申请锁的事务将进行等待,直到锁被其他事务释放。

可能出现的问题:

  • 死锁:多个事务持有锁并互相循环等待其他事务的锁导致所有事务都无法继续执行。


  • 饥饿:数据项A一直被加共享锁,导致事务一直无法获取A的排他锁。

对于可能发生冲突的并发操作,锁使它们由并行变为串行执行,是一种悲观的并发控制。

2.3.2 基于时间戳的并发控制

核心思想:对于并发可能冲突的操作,基于时间戳排序规则选定某事务继续执行,其他事务回滚。

系统会在每个事务开始时赋予其一个时间戳,这个时间戳可以是系统时钟也可以是一个不断累加的计数器值,当事务回滚时会为其赋予一个新的时间戳,先开始的事务时间戳小于后开始事务的时间戳。

每一个数据项Q有两个时间戳相关的字段:

  • W-timestamp(Q):成功执行write(Q)的所有事务的最大时间戳

  • R-timestamp(Q):成功执行read(Q)的所有事务的最大时间戳

时间戳排序规则如下:

假设事务T发出read(Q),T的时间戳为TS

  1. 若TS(T)<w-timestamp(q),则t需要读入的q已被覆盖。此

  2. read操作将被拒绝,T回滚。

  3. 若TS(T)>=W-timestamp(Q),则执行read操作,同时把R-timestamp(Q)设置为TS(T)与R-timestamp(Q)中的最大值


假设事务T发出write(Q)

  1. 若TS(T)<r-timestamp(q),write操作被拒绝,t回滚

  2. 若TS(T)<w-timestamp(q),则write操作被拒绝,t回滚

  3. 其他情况:系统执行write操作,将W-timestamp(Q)设置为TS(T)

基于时间戳排序和基于锁实现的本质一样:对于可能冲突的并发操作,以串行的方式取代并发执行,因而它也是一种悲观并发控制。

它们的区别主要有两点:

  • 基于锁是让冲突的事务进行等待,而基于时间戳排序是让冲突的事务回滚。

  • 基于锁冲突事务的执行次序是根据它们申请锁的顺序,先申请的先执行;而基于时间戳排序是根据特定的时间戳排序规则。


2.3.3 基于有效性检查的并发控制

核心思想:事务对数据的更新首先在自己的工作空间进行,等到要写回数据库时才进行有效性检查,对不符合要求的事务进行回滚。

基于有效性检查的事务执行过程会被分为三个阶段:

  1. 读阶段:数据项被读入并保存在事务的局部变量中。所有write操作都是对局部变量进行,并不对数据库进行真正的更新。

  2. 有效性检查阶段:对事务进行有效性检查,判断是否可以执行write操作而不违反可串行性。如果失败,则回滚该事务。

  3. 写阶段:事务已通过有效性检查,则将临时变量中的结果更新到数据库中。

有效性检查通常也是通过对事务的时间戳进行比较完成的,不过和基于时间戳排序的规则不一样。

该方法允许可能冲突的操作并发执行,因为每个事务操作的都是自己工作空间的局部变量,直到有效性检查阶段发现了冲突才回滚。因而这是一种乐观的并发策略。

2.3.4 基于快照隔离的并发控制

快照隔离是多版本并发控制(mvcc)的一种实现方式。

其核心思想是:数据库为每个数据项维护多个版本(快照),每个事务只对属于自己的私有快照进行更新,在事务真正提交前进行有效性检查,使得事务正常提交更新或者失败回滚。

由于快照隔离导致事务看不到其他事务对数据项的更新,为了避免出现丢失更新问题,可以采用以下两种方案避免:

  • 先提交者获胜:对于执行该检查的事务T,判断是否有其他事务已经将更新写入数据库,是则T回滚否则T正常提交。

  • 先更新者获胜:通过锁机制保证第一个获得锁的事务提交其更新,之后试图更新的事务中止。

事务间可能冲突的操作通过数据项的不同版本的快照相互隔离,到真正要写入数据库时才进行冲突检测。因而这也是一种乐观并发控制。

故障与故障恢复


3.1 为什么需要故障恢复技术

数据库运行过程中可能会出现故障,这些故障包括事务故障和系统故障两大类

  • 事务故障:比如非法输入,系统出现死锁,导致事务无法继续执行。

  • 系统故障:比如由于软件漏洞或硬件错误导致系统崩溃或中止。

这些故障可能会对事务和数据库状态造成破坏,因而必须提供一种技术来对各种故障进行恢复,保证数据库一致性,事务的原子性以及持久性。

数据库通常以日志的方式记录数据库的操作从而在故障时进行恢复,因而可以称之为日志恢复技术。

3.2 事务的执行过程以及可能产生的问题

"Dry Technology" Ali wrote to the architect engineer Java database transactions


事务的执行过程可以简化如下:

  1. 系统会为每个事务开辟一个私有工作区

  2. 事务读操作将从磁盘中拷贝数据项到工作区中,在执行写操作前所有的更新都作用于工作区中的拷贝.

  3. 事务的写操作将把数据输出到内存的缓冲区中,等到合适的时间再由缓冲区管理器将数据写入到磁盘。

由于数据库存在立即修改和延迟修改,所以在事务执行过程中可能存在以下情况:

  1. 在事务提交前出现故障,但是事务对数据库的部分修改已经写入磁盘数据库中。这导致了事务的原子性被破坏。

  2. 在系统崩溃前事务已经提交,但数据还在内存缓冲区中,没有写入磁盘。系统恢复时将丢失此次已提交的修改。这是对事务持久性的破坏。

3.3 日志的种类和格式

  • <T,X,V1,V2>:描述一次数据库写操作,T是执行写操作的事务的唯一标识,X是要写的数据项,V1是数据项的旧值,V2是数据项的新值。


  • <T,X,V1>:对数据库写操作的撤销操作,将事务T的X数据项恢复为旧值V1。在事务恢复阶段插入。

  • <T start>: 事务T开始

  • <T commit>: 事务T提交

  • <T,abort>: 事务T中止

关于日志,有以下两条规则

  1. 系统在对数据库进行修改前会在日志文件末尾追加相应的日志记录。

  2. 当一个事务的commit日志记录写入到磁盘成功后,称这个事务已提交,但事务所做的修改可能并未写入磁盘


3.4 日志恢复的核心思想

  • 撤销事务undo:将事务更新的所有数据项恢复为日志中的旧值,事务撤销完毕时将插入一条<T abort>记录。

  • 重做事务redo:将事务更新的所有数据项恢复为日志中的新值。

事务正常回滚/因事务故障中止将进行redo,系统从崩溃中恢复时将先进行redo再进行undo。

以下事务将进行undo:日志中只包括<T start>记录,但既不包括<T commit>记录也不包括<T abort>记录.

以下事务将进行redo:日志中包括<T start>记录,也包括<T commit>记录或<T abort>记录。

假设系统从崩溃中恢复时日志记录如下

"Dry Technology" Ali wrote to the architect engineer Java database transactions


由于T0既有start记录又有commit记录,将会对事务T0进行重做,执行相应的redo操作。

由于T1只有start记录,将会对T1进行撤销,执行相应的undo操作,撤销完毕将写入一条abort记录。

3.5 事务故障中止/正常回滚的恢复流程

  1. 从后往前扫描日志,对于事务T的每个形如<T,X,V1,V2>的记录,将旧值V1写入数据项X中。

  2. 往日志中写一个特殊的只读记录<T,X,V1>,表示将数据项恢复成旧值V1,这是一个只读的补偿记录,不需要根据它进行undo。

  3. 一旦发现<T start>日志记录,就停止继续扫描,并往日志中写一个

  4. <T abort>日志记录。


"Dry Technology" Ali wrote to the architect engineer Java database transactions



3.6 系统崩溃时的恢复过程(带检查点)

检查点是形如<checkpoint L>的特殊的日志记录,L是写入检查点记录时还未提交的事务的集合

System to ensure that the transaction database changes before the checkpoint has been submitted already written to disk, do not need to redo. Checkpoints can speed up the recovery process.

Ben collapse of the recovery process when the system is divided into two phases: Phase redo and undo phases.

Redo stages:

  1. A list of transactions from the last checkpoint system starts forward scan log will redo the undo-list to the list of L checkpoint log record.

  2. Found <T, X, V1, V2> the renewal recording or <T, X, V> compensation undo records, to redo the operations.

  3. Found <T start> record, put T was added to the undo-list.

  4. Found <T abort> or <T commit> record, put T are removed from the undo-list.

Undo stages:

  1. The system scans the log in reverse, starting from the tail

  2. Logging found to belong to undo-list of a transaction, to execute the undo operation

  3. Found undo-list in the transaction T <T start> record, it writes a <T abort> record,

  4. And T is removed from the undo-list in.

  5. undo-list is empty, the withdrawal phase ends

Summary : first update log records of all transactions in order to redo it again, in the implementation of its operations for the update operation needs to undo the undo transaction in reverse order.

3.6.1 example of a system crash recovery

Before the recovery log as follows, after the last log record written to system crashes

"Dry Technology" Ali wrote to the architect engineer Java database transactions


"Dry Technology" Ali wrote to the architect engineer Java database transactions



to sum up

Transactional database system is the basic unit of concurrency control, the database system is the basic unit of failover, thus maintaining the database state is consistent base unit.

ACID is a basic feature of the transaction, the database system is to be guaranteed ACID transaction concurrency control techniques and by log recovery techniques, can be obtained following the concept about the architecture of the database transaction.

"Dry Technology" Ali wrote to the architect engineer Java database transactions


 


Guess you like

Origin blog.51cto.com/14480698/2428151