扫地僧又偷摸去面试了,这次面试官竟然把它问懵逼了!
面试问题
数据库的ACID是什么?
ACID是DBMS在写入或更新信息时为保证事务正确可靠所必须具备的四个特性。
- Atomic:原子性,即所有操作要么全部成功,要么全部不成功,不存在部分操作成功,部分操作失败的情况。
- Consistency:一致性,即事务执行前后数据库必须保持数据的合法性和正确性,比如满足主键约束、唯一性约束等。
- Isolation:隔离性,即事务间并发执行时互不影响,相互隔离。
- Durability:持久性,即事务一旦提交成功,则它对数据库的修改就永久保留,宕机重启等异常数据也不会丢失。
上面的问题回答的没问题,但是后面的问题扫地僧回答的一塌糊涂。
可以具体解释下ACID吗?
原子性:事务的所有操作要么全部成功,要么全部失败,不会存在中间态。
比如A给B转100元时,包含两个操作:A账户扣减100元,B账户增加100元。这两个操作必须要作为一个事务执行,保证A和B的帐户加减要么都成功要么都失败。
在Mysql中,通过Undo日志来保证原子性:在执行数据修改前,都会将原数据写入到Undo日志中,当事务失败或RollBack时,通过Undo日志进行恢复。一致性:事务在执行过程中,必须满足预定义的业务规则和约束(如唯一性约束)。因业务实现bug导致数据不正确不属于违反事务的一致性,因为DB只保证事务执行正确,不保证业务正确。
在Mysql中,一致性是综合结果,由原子性、隔离性、持久性共同保证的,原子性和隔离性保证数据的正确性,持久性保证事务完成后数据不会丢失,其中原子性保证数据不出现中间态,隔离性保证事务执行期间不受其他事务干扰。隔离性:多个事务并发执行互不影响,相互隔离,隔离本质上也是数据的可见性。当没有隔离时,会存在脏读、不可重复读、幻读等经典问题。为此,数据库提供了四种隔离级别:
- 未提交读(Read Uncommitted)不解决任何问题,并发性最高、性能最高。
- 已提交读(Read Committed)解决了脏读问题。
- 可重复读(Repeatable Read)解决了脏读和不可重复读问题。
- 串行读(Serializable)解决脏读、不可重复读和幻读问题,并发性最低,性能最差。
在Mysql中,通过锁机制实现事务间的隔离性,默认的隔离级别是可重复读(Repeatable Read),但其通过MVCC+Gap锁解决了幻读问题。
持久性:事务一旦提交,它对数据库的修改就永久保留,即使数据库崩了、宕机重启数据也不能丢。
在Mysql中,通过Redo日志来保证持久性:在事务提交前,会将所有修改写入Redo日志文件中(物理日志),并刷盘,确保写入磁盘成功。当数据库崩溃、宕机重启时,可以通过Redo日志恢复提交成功的事务。
隔离性中多个事务执行互不影响,为什么操作同一个数据的事务会阻塞另一事务?
隔离性就是通过锁机制实现的,这里多个事务执行互不影响是指逻辑上互不影响,不是指物理上互不影响。
ACID和CAP中的C有什么区别?
虽然ACID和CAP中的C都表示一致性,但ACID中的C侧重数据合法性和正确性,而CAP中的C侧重多个数据副本间的一致性。
附录
隔离三个经典问题
- 脏读(Dirty Read):读取另一个事务未提交的数据
- 不可重复读(Non-Repeatable Read):一个事务中,前后查询了两次,但两次读到的数据不一样,因为被其他事务修改了。
- 幻读(Phantom Read):一个事务中,前后查询了两次,但两次读到的数据条目数不一致,因为其他事务插入了新记录。
Mysql Redo日志刷盘时机
Mysql提供innodb_flush_log_at_trx_commit参数控制刷盘机制,取值:
- 1:每次事务提交都刷盘,最安全,性能最差
- 0: 每秒刷盘一次
- 2: 依赖系统异步刷盘,性能最高,最不安全