事务(Transaction):一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中的各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL、C++或Java)书写的用户程序的执行所引起的,并用形如Begin Transaction 或 End Transation语句(或者函数调用)来界定。事务由事务开始(Begin Transation)和事务结束(End Transation)之间执行的全体操作组成。
一丶事务是指?
数据库中的事务是指对数据库执行的一批DML操作(INSERT、UPDATE、DELETE),在同一个事务当中,这些操作最终要么全部成功要么全部失败,不会存在部分成功的情况。在Mysql中,只有InnoDB引擎的数据库或表才支持事务。
二、事务及其ACID属性
- 原子性(Atomicity):把一组操作(一个事务)看成一个整体,这组操作要么全部成功,或者全部失败,不可分割。比如一个service方法中对数据库做了两个写操作,那么这2个写操作需要都成功,一旦某个动作失败就需要全部回滚。
- 一致性(Consistency):一致性要求任何写到数据库的数据都必须满足于预先定义的规则(数据不能出错),简单来说就是任何时间点都不能出现违反一致性要求的状态。比如:A账户扣减100块,B账户增加100块,如果A扣减成功,B增加失败,那么数据就会出现问题,和我们预先定义的规则不一致。
- 隔离性(Isolation):多个事务之间是相互隔离的,如果多个事务同时执行产生了影响就可能会出现各种并发问题,比如:脏读,幻读等,针对于不同的并发问题可以通过不同的事务隔离级别来解决。
- 持久性(Durability):持久性关键在于一旦“完成提交”(committed),那么数据就不会丢失。即使Mysql重启或者宕机数据依然不会丢失,因为数据已经被持久化到磁盘。
三、事务的实现
事务是实现是基于数据库引的存储引擎,不同的存储引擎对事务的支持程度不一样。Mysql中支持事务的存储引擎有InnoDB,MyISAM;事务的实现就是如实实现ACID的特性。
- 事务的隔离性就是通过锁实现的;(后续我会专门介绍mysql的各种锁)
- 事务的原子性、一致性和持久性则是通过事务日志实现
- 事务日志:包括重做日志redo log和回归日志 undo log,两种日志均可以视为一种恢复操作,他们的作用不同,redo log是恢复提交事务修改的操作,而undo log是回滚记录到特性版本。它们记录的内容也不同,redo log是物理日志,记录的是物理修改操作,而undo log是逻辑日志,根据每行进行记录;
- Mysql通过redo log实现持久性:在InnoDB引擎中,redo log记录的是新数据的备份。在事务提交前,现将redo log 持久化,当系统崩溃时,虽然数据没有持久化,但是redo log已经持久化了。系统可以根据redo log的内容,将所有数据恢复到最新状态。至于数据会异步方式刷新磁盘到Mysql磁盘文件。
- Mysql是利用InnoDB的undo log 来实现的原子性:undo log 名为回滚日志,是实现原子性的关键,当事务回滚能够撤销所有已经成功执行的sql语句,他需要记录你要回滚的相应日志信息。
四、事务的并发问题
Mysql作为多线程并发访问的数据库,其明显的特点是资源可以被多个用户共享访问。当多个用户同时访问相同的数据库资源时,如果事务之间没有采取必要的隔离措施,可能会常出现以下四种不确定的情况。
- 脏读(Dirty Read):事务B读取到了事务A未提交的数据,事务A回滚,事务B读取到的数据就是脏数据;解決办法设置事务隔离级别为可重复读或串行化;
- 幻读(Phantom Read):事务B以相同的条件读取多次数据读取到的数据条数不一致,通常是因为在多次读之间别的事务insert了数据导致多次读到相同条件的数据条数不一样;
- 不可重复读(Non-Repeatable Read):在同一事务中对同一个数据多次读取到的结果不一致,通常是因为两次读之间其他事务修改了该数据;
- 丢失更新(Lost Update):事务并发写的情况B事务的update覆盖了A事务的update,这叫覆盖丢失更新,还有一种是数据回滚丢失更新;
-- 设置事务隔离级别为可重复读
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 设置事务隔离级别为串行化
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
五、事务的隔离级别
为了避免上述几种问题的发生,Mysql为事务定义了不同的隔离级别,以此来保证数据的稳定性。事务隔离级别由低到高可分为Read Uncommitted(读未提交)、Read Committed(读已提交)、Repeatable Read(可重复度)、Serializable(可串行化)。
- Read Uncommitted(读未提交):允许事务读取其他事务未提交的结果(即允许脏读)。是事务隔离级别中等级最低的,也是最危险的,该级别很少实际应用;
- Read Committed(读已提交):允许事务只能读取其他事务已经提交的结果,该隔离级别可以避免脏读,但不能避免重复读和幻读情况;
- Repeatable Read(可重复读):该级别确保了同一事务的多个实例在并发读取数据时,可以读取到同样的数据行。这种级别可以避免脏读和不可重复读,但不能避免幻读问题,是Mysql默认的隔离级别;
- Serializable(可串行化):强制性的对事物进行排序,使之不可能相互冲突,从而解决幻读问题。实际上,这种方式是在每个读的数据行上加了共享锁,但这种级别可能会导致大量的超时现象和锁竞争,所以很少用于实际应用,识时务级别中最高等级的;
注意:事务的隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也会响应增大。另外,不同的隔离级别可能会造成不同的并发异常;
不过Mysql的存储引擎通过多版本的并发控制(MultiVersion Concurrency Control,MVCC)机制解决了数据幻读的问题。因此,当Mysql隔离级别为Repeatable Read(可重复读)时,是可以避免幻读问题的出现;
结尾:喜欢的朋友点个赞吧!!!