事务是什么?
事务用来维护数据库数据的完整性,它保障成批的sql要么全部执行,要么全部不执行。
事务的ACID特性
Atomicity 原子性。原子性是 事物是不可分割的最小的单元,事物内的所有操作,要么全部提交成功,要么全部失败回滚。例如:A帐户向B帐户 转账1000元,则先检查A账户余额是否有1000元,然后将A账户的余额减少1000,再将B账户的余额增加1000,这两个动作要么都提交成功,要么都回退,不可能发生一个有效、一个无效的情况。
Consistency 一致性。一致性是 事物执行前数据库的数据处于正确状态,事物执行后数据库的数据仍处于正确状态。(如:a账户转账给b账户,不能出现a账户扣钱了而b账户没有收到200)
Isolation 隔离性。隔离性是 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。这需要事物的隔离级别来指定事物的隔离性。例如:在A、B之间转帐时,C同时向A转帐,若同时进行则A、B之间的一致性不能得到满足。所以在A、B事务执行过程中,其他事务不能访问(修改)当前相关的数值。
Durability 永久性。永久性是 事务一旦提交,对数据库的数据改变必须是永久的,就是说修改后的数据永久性的保存到数据库中,不会因为遇到系统故障或断电造成数据不一致或丢失。在提交之前如果系统故障,则所有信息全部丢失。提交之后数据存放在磁盘中,是永久性的。
事务并发带来的问题
1)丢失更新 Lost Update:(没有加锁)
两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的。
2)脏读Dirty Reads:(没有隔离)
一个事务看到了另外一个事物没有提交的更新数据。这是事务没有隔离造成的。
3)不可重复读:Non-Repeatable Reads
在同一事务中,多次读取同一数据但是返回不同的结果,也就是有其他事务更改了这些数据。
4)幻读:Phantom Reads 并发造成的
一个事务在执行过程中读取到另一个事务已提交的插入数据。就是说在第一个事务开始时,读取到一批数据,但是伺候另一个事务又插入新数据并提交,此时第一个事务又读取到这批数据但是发现多出了一条,貌似产生幻觉一样。这是并发造成的。
通过设置隔离级别isolation level来解决并发问题。
事务的四种隔离级别:
1)未提交读(Read Uncommitted):一个事务能够读取到 别的事务中没有提交的更新数据。事务可以读取到未提交的数据,这也被称为脏读(dirty read)。
所以这种级别很有可能读到脏数据,隔离级别最低。
2)提交读(Read Committed):一个事务只能读取到别的事务提交的更新数据。
一般我们提交读就可以了。只能读取到已经提交的数据。即解决了脏读,但未解决不可重复读。(oracle默认的)
3)可重复读(Repeated Read):保证同一事务中先后执行的多次查询将返回同意结果,不受其他事务的影响。这种隔离级别可能出现幻读。(mysql默认的)
4)序列化(Serializable):不允许事务并发执行,强制事务串行执行,就是在读取的每一行数据上都加上了锁,读写相互都会阻塞。这种隔离级别最高,是最安全的,性能最低,不会出现脏读,不可重复读,幻读,丢失更新。
如何设置隔离级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; //设置提交读隔离级别
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; //设置序列化隔离级别
事务的(ACID)特性是由关系数据库管理系统(RDBMS,数据库系统)来实现的。
数据库管理系统采用 重执行日志 来保证事务的原子性、一致性和持久性。日志记录了事务对数据库所做的更新,如果某个事务在执行过程中发生错误,就可以根据日志,撤销事务对数据库已做的更新,使数据库退回到执行事务前的初始状态。
数据库管理系统采用数据库锁机制来实现事务的隔离性。当多个事务同时更新数据库中相同的数据时,只允许持有锁的事务能更新该数据,其他事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新该数据。