ACID,指的是在数据库事务正确执行的四个基本要素的缩写。
具体解释:
原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
任何一个数据库事务必须满足ACID,只有这样才能保证在事务执行过程中的正确性。
事务,指的是作为单个逻辑工作单元执行的一组操作(数据库操作),要么全部成功,要么全部失败。
本地事务,指数据库事务或传统事务。一次事务只连接一个支持事务的数据库;事务的执行结果保证ACID。
分布式事务,指在分布式环境中一次操作由多个系统协调完成,可能涉及到多个数据库的写操作(多数据源),分布式事务就是为了保证不同数据库(多数据源)的数据一致性。
原子性(Atomicity)
原子性其实非常好理解,我认为它指的就是一种完整性,就是说任何一个具备原子性的事务只有两种状态:完成操作 和 未操作。原子性保证事务的一切操作要么一起成功要么一起失败。原子性的事务一旦开始就一直运行到结束,它不会被线程调度机制中断。如果遇到强制中断,就会全部回滚到最初未操作的状态。还有一种说法是:“原子操作(atomic operation)是不需要”。
利用Innodb的undolog(日志回滚),实现原子性。当事务回滚时能够撤销所有已经成功执行的sql语句,它需要记录回滚的相应日志信息(undolog记录的是操作之前的数据)。
一致性(Consistency)
这个是数据库事务的核心,它是数据库最基本的特性。这条特性看起来简单,但是理解起来还是比较复杂的。
它的书面定义是:一致读 和 一致写
一致读:事务读取数据只能从一个状态中读取,不能从2个或者2个以上状态读取
一致写:事务执行的数据变更只能基于一个一致的状态,且只能体现在一个状态中。
事务必须是使数据库从一个一致性状态变到另一个一致性状态,一致性的定义和完整性约束(主键、外键约束、自定义约束等)有关。事务执行的前后都是合法的数据状态,不能违背任何的数据完整性。
隔离性(Isolation)
一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能相互干扰。
数据并发读写中存在三大致命的问题:
(1)脏读:
读到了其他事务未提交的数据(未提交意味着这些数据可能会回滚,可能最终不会存到数据库)。
(2)不可重复读:
同一个事务多次使用相同条件读取到的数据是不一样的(通常针对更新update操作)。
PS:可重复读,是MySQL默认的事务隔离策略(级别)解决了幻读问题,它使用到了“间隙锁”。
(3)幻读:
事务A按照一定条件进行数据读取,期间事务B插入/删除相同搜索条件的新数据,事务A再次按照原先条件进行读取,发现事务B新插入的数据;事务A两次读取相同条件的数据读取到的条数不一样(通常针对插入insert和删除delete操作)。
持久性(Durability)
一个事务一旦提交,它对数据库中数据的改变应该是永久性的,数据不会丢失。
通过Innodb的redolog,实现持久性。如果涉及到多个操作的数据,都会存到redolog中,最终将redolog的数据持久化到磁盘;在事务提交前,将redolog持久化。
标准SQL隔离级别
隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(read uncommitted) | 可能 | 可能 | 可能 |
读已提交(read committed) | 不可能 | 可能 | 可能 |
可重复读(repeatable reads) | 不可能 | 不可能 | 可能(MySQL不可能) |
串行读(serializable) | 不可能 | 不可能 | 不可能 |
完全串行读,它将事务的执行变为顺序执行,相当于单线程,后一个事务的执行必须等待前一个事务结束,隔离效果最好,但带来性能开销,影响系统性能。
MySQL事务隔离其实是依赖锁来实现的,读未提交隔离级别,不加锁,性能最好,但解决不了问题。
Spring五大事务隔离级别和七大事务传播行为