一、事务的基本概念
1.1 什么是事务?
事务是由一条或者多条对数据库操作的SQL语句所组成的一个不可分割的单元,只有当事务中的所有操作都正常执行完了,整个事务才会被提交给数据库;如果有部分事务处理失败,那么事务就要回退到最初的状态,因此,事务要么全部执行成功,要么全部失败。
1.2 为什么要有事务?
当需要对数据表执行一系列多个操作的情况下,为了防止这些操作中的部分操作执行成功而另一些操作 执行失败,从而导致数据不正确,就需要使用事务。(对错误进行修改)
1.3 事务的基本操作?
开启事务: begin 或者 start transaction
提交事务: commit
回滚整个事务: rollback
设置保存点: savepoint 保存点名称
回滚到具体的保存点: rollback to 保存点名称
二、ACID特性及其原理
ACID是衡量事物的四个特性:
2.1 事务的原子性(Atomic):
事务是一个不可分割的整体,事务必须具有原子特性,及当数据修改时,要么全执行,要么全不执行 ,即不允许事务部分的完成。
原子性的实现原理:Undo log
2.2 事务的一致性(Consistency):
事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态。
事务的一致性实现原理 = 原子性原理 + 隔离性原理 + 持久性原理
如果其他三个特性能够保证,一致性一定可以保证
2.3 事务的隔离性(Isolation):
当两个或者多个事务并发执行时,为了保证数据的安全性,将一个事物内部的操作与其它事务的操作隔离起来,不被其它正在执行的事务所看到。隔离性使得每个事务的更新在它被提交之前,对其它事务都是不可见的。
隔离性实现原理:mysql锁机制 + MVCC机制
2.2 事务的持久性(Durability):
事务完成以后,DBMS保证它对数据库中的数据的修改是永久性的,即使数据库因为故障出错,也应该能够恢复数据!(其它操作或故障不应该对其执行结果有任何影响)
持久性的实现原理 redo log
三、脏读、不可重复读和幻读以及事物的隔离级别
3.1 脏读(Dirty Read):
一个事务读取了另一个事务未提交的数据。
例如当事务A和事务B并发执行时,当事务A更新后,事务B查询读取到A尚未提交的数据,此时事务A回滚,则事务B读到的数据就是无效的脏数据。(事务B读取了事务A尚未提交的数据)
3.2 不可重复读(NonRepeatable Read):
一个事务的操作导致另一个事务前后两次读取到不同的数据。
例如当事务A和事务B并发执行时,当事务B查询读取数据后,事务A更新操作更改事务B查询到的数据,此时事务B再次去读该数据,发现前后两次读的数据不一样。(事务B读取了事务A已提交的数据)
3.3 虚读(Phantom Read)/幻读:
一个事务的操作导致另一个事务前后两次查询的结果数据量不同。
例如当事务A和事务B并发执行时,当事务B查询读取数据后,事务A新增或者删除了一条满足事务B查询条件的记录,此时事务B再去查询,发现查询到前一次不存在的记录,或者前一次查询的一些记录不见了。(事务B读取了事务A新增加的数据或者读不到事务A删除的数据)
脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。
不可重复读与幻读的区别可以通俗的理解为:前者是数据变了,后者是数据的行数变了.
3.4 事务隔离级别
为解决脏读、不可重复读和幻读的问题就需要使用事物的隔离性,设置事务的隔离级别。首先隔离性一共分了4种隔离级别。分别是:未提交读,已提交读,可重复读,和序列化。
表示不支持事务:TRANSACTION_NONE
未提交读:TRANSACTION_READ_UNCOMMITTED
说明在提交前一个事务可以看到另一个事务的变化。这样读”脏”数据,不可重复读和虚读都是被允许的。
已提交读:TRANSACTION_READ_COMMITTED
说明读取未提交的数据是不允许的。这个级别仍然允许不可重复读和虚读产生。
可重复读:TRANSACTION_REPEATABLE_READ
说明事务保证能够再次读取相同的数据而不会失败,但虚读仍然会出现。
可序列化/串行化:TRANSACTION_SERIALIZABLE
是最高的事务级别,它防止读脏数据,不可重复读和虚读。
四、隔离性试下原理:锁机制 +和MVCC机制
MySQL锁机制:
MyIsam : 当操作数据时,MyIsam引擎下锁住的是整张表。所以称之为表锁。
InnoDB : InnoDB的锁相比于MyIsam有些特殊:它既支持行锁也支持表锁。原因就是InnoDB的行锁是根据索引项的记录添加的,只有通过索引条件检索数据,InnoDB才使用行级锁,否则InnoDB将使用表锁。
Record Locks(记录锁):在索引记录上加锁。
Gap Locks(间隙锁):在索引记录之间加锁,或者在第一个索引记录之前加锁,或者在最后一个索引记录之后加锁。·
Next-Key Locks:在索引记录上加锁,并且在索引记录之前的间隙加锁。它相当于 是Record Locks与Gap Locks的一个结合
共享读锁和排他写锁:·
共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。·
排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的。
行锁和表锁:
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。·
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
MVCC机制:
mvcc机制就是尽量的不去使用这些锁,一旦这些锁加上之后事务与事务之间就变成了完全的串行执行,在隔离级别中串行化其实就是这样做的。
InnoDB的一致性的非锁定读就是通过在MVCC实现的,Mysql的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,它们一般都同时实现了多版本并发控制(MVCC)。
MVCC的实现,是通过保存数据在某一个时间点的快照来实现的,每一个事务只操作自己版本下的数据。因此每一个事务无论执行多长时间看到的数据都是一样的。所以MVCC实现可重复读。