atomicity
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
事务是一个原子操作, 由一系列动作组成。 组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作执行成功,整个事务才提交。
事务中的任何一个数据库操作失败,已经执行的任何操作都必须被撤销,让数据库返回初始状态。
consistency
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
一旦所有事务动作完成, 事务就被提交。数据和资源就处于一种满足业务规则的一致性状态,即数据不会被破坏。
比如a+b=100,一个事务改变了a比如增加了a的值,那么必须同时改变b,保证在事务结束以后a+b=100依然成立,这就是一致性。
isolation
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
在并发数据操作时,不同的事务拥有各自的数据空间,它们的操作不会对对方产生干扰。准确地说,并非要求做到完全无干扰。
数据库规定了多种事务隔离级别,不同的隔离级别对应不用的干扰程度。隔离级别越高,数据一致性越好,但并发行越弱。
比如对于A对B进行转账,A没把这个交易完成的时候,B就不知道A要给他转多少钱。
durability
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
数据库管理系统一般采用重执行日志来保证原子性、一致性和持久性。
重执行日志记录了数据库变化的每一个动作,数据库在一个事务中执行一部分操作后发生错误退出,数据库即可根据重执行日志撤销已经执行的操作。对于已经提交的事务即使数据库崩溃,在重启数据库时也能根据日志对尚未持久化的数据进行相应的重执行操作。
一个事务与其他事务隔离的程度称为隔离级别。
数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制,
就会导致各种并发问题。
隔离级别 | 存在问题 |
---|---|
READ UNCOMMITTED | 脏读、不可重复读、幻读 |
READ COMMITTED | 不可重复读、幻读 |
REPEATABLE READ | 幻读 |
SERIALIZABLE | 无 |
这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。
另外四个与JDBC的隔离级别相对应。大部分数据库的默认级别都是READ_COMMITTED(读取已提交)。
这是事务最低的隔离级别,允许当前事务读取未被其他事务提交的变更。
这种隔离级别会产生脏读,不可重复读和幻读。
产生脏读场景:A事务读取一个字段,但是这个字段被另外一个事务更新却未提交,
再次读取该字段时如果另外一个事务回滚则出现了脏读现象(读到的数据与第一次,
数据库中的数据都不同)。
产生不可重复读场景:A事务读取一个字段,但是这个字段被另外一个事务更新并提交,
再次读取该字段值不一样则出现了不可重复读现象(同一个事务中,不能保证读取的字段值相同)。
产生幻读场景:A事务读取一个字段集合,但是这个表被另外一个事务更新并提交(如插入了几行),
再次读取该表可能会多几行则出现了幻读现象。
保证一个事务修改的数据提交后才能被另外一个事务读取,
另外一个事务不能读取该事务未提交的数据。可以避免脏读,但不可重复读和幻读的现象仍然可能出现。
不可重复读
A事务读取一个字段,但是这个字段被另外一个事务更新并提交,再次读取该字段值不一样则出现了不可重复读现象(同一个事务中,不能保证读取的字段值相同)。
举例就是对于一个数A原来是50,然后提交修改成100,这个时候另一个事务在A提交修改之前,
读取到了A是50,刚读取完,A就被修改成100了,这个时候另一个事务再进行读取发现A就突然变成100了
幻读
读取一个字段,但是这个表被另外一个事务更新并提交(如插入了几行),再次读取该表可能会多几行则出现了幻读现象。
确保事务可以多次从某行记录的一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新。这种事务隔离级别可以防止脏读,不可重复读,但是可能出现幻读。
它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了在一个事务过程,
读取的数据不会发生变化(即使数据库中的数据在该事务过程中发生了变化)。
在并发情况下和串行化的读取的结果是一致的,没有什么不同。这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。但性能十分低下!
脏读: 对于两个事务 T1, T2。T1 读取了已经被 T2 更新但还没有被提交的字段。之后, 若 T2 回滚, T1读取的内容就是临时且无效的,也就是脏数据。
不可重复读:对于两个事务 T1, T2。 T1 读取了一个字段, 然后 T2 更新了该字段。之后, T1再次读取同一个字段, 值就不同了。
幻读:事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一些新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这些多出来的新纪录就是幻读。
不可重复读和幻读的区别:
不可重复读重点是在update,即事务前后对比特定数据内容的修改。而幻读是insert和delete,即事务前后数据结果集的对比。
Oracle数据库支持READ COMMITTED(默认) 和 SERIALIZABLE这两种事务隔离级别。所以Oracle不会出现脏读。
MySQL 支持 4 种事务隔离级别:READ_UNCOMMITTED(读取未提交),READ_COMMITTED(读取已提交),REPEATABLE_READ(可重复读-默认)和SERIALIZABLE (可串行化)。
Oracle 默认使用的是READ_COMMITTED(读已提交)。MySQL默认事务隔离级别为 REPEATABLE_READ(可重复读)。