事务的特性(ACID)
原子性(Atomicity)
一个事务的操作要么全部成功,要么全部失败。
例如事务内有两个操作:
insert into student (id,name,age) values (1,'zhangsan',18);
update student set age = 20 where id = 2;
如果其中任意一条sql执行失败,则这两条sql都要失败,不能成功更新数据。
一致性(Consistency)
一致性,其实就是要保证结果是预期要达到的结果。而原子性、隔离性和持久化就是为了保证数据的一致性。
隔离性(Isolation)
官网描述:
Transaction isolation is one of the foundations of database processing. Isolation is the I in the acronym ACID; the isolation level is the setting that fine-tunes the balance between performance and reliability, consistency, and reproducibility of results when multiple transactions are making changes and performing queries at the same time.
事务之间数据操作要有一定的不可见性,这个和数据库引擎的隔离级别有一定的关系。Innodb有以下四种隔离级别:
- READ UNCOMMITTED(读未提交)
该隔离级别可以读到其它事务还未提交的数据,也就是脏读。该隔离级别数据一致性最低,但是性能最高。
- READ COMMITTED(读已提交)
其它事务已经提交的数据,当前事务可以读取到。该隔离级别能解决脏读问题,但是还存在不可重复读问题。
- REPEATABLE READ(可重复读)
该隔离级别解决了脏读、不可重复读的问题,但是还有一种幻读问题:当范围查询的时候,其它事务提交的数据,会被当前事务查到,两次读取的结果数量不一致。Innodb解决了快照读(select)的幻读问题。
- SERIALIZABLE(串行化)
引擎对写加写锁、读加读锁,事务只能按顺序执行,上一个事务执行完成后,才能执行下一个事务。所以该隔离级别数据一致性最高,但是数据库性能最低。
持久性(Durability)
就是将数据存储到磁盘中去。
Innodb怎么保证原子性的?
Innodb是使用undoLog来保证原子性的。事务内的操作会在修改数据的同时在undoLog中产生一条记录。当该事务执行rollback的时候,存储引擎会执行undoLog内的语句来进行回滚,恢复到之前的数据。
在Innodb当中,INSERT操作在事务提交前只对当前事务可见,Undo log在事务提交后即会被删除,因为新插入的数据没有历史版本,所以无需维护Undo log。而对于UPDATE、DELETE,责需要维护多版本信息。 在InnoDB当中,UPDATE和DELETE操作产生的Undo log都属于同一类型:update_undo。(update可以视为insert新数据到原位置,delete旧数据,undo log暂时保留旧数据。
Innodb怎么实现隔离性的?
- read-view:数据库在有隔离的情况下都是从read-view中读取数据的。在不同的隔离级别下,read-view的创建时机是不同的。在可重复读的隔离级别下,read-view实在事务开始的时候创建的,也就是事务内的读是快照读;在读已提交的隔离级别下,read-view是在sql执行的时候创建的,也就是当前读;在读未提交的隔离级别下,不会创建read-view,直接返回记录上的最新值。
- 水位:事务创建的的时候,会生成一个链表。链表中存储的是所有当前活跃事务的id。
- 更新操作的可见性:数据更新时,必须是在当前的最新的数据上修改,否则某些事务的更新就会被覆盖。因此,事务中的更新操作必须是当前读。这就和我们上面说的一致性读产生了矛盾,或者说是有别于一致性读。此时就要引入行锁,当数据修改,但没有提交时,行锁是一直持有的。因此其他事务的更新操作是会被阻塞的。因此,行锁保证了当前读,也就保证了数据的修改不会被覆盖。
- 锁