ACID模型是一组强调可靠性的数据库设计原则,这对于业务数据和任务关键型应用程序非常重要。MySQL包括InnoDB存储引擎等组件,它严格遵循ACID模型,因此数据不会被破坏,结果不会因软件崩溃和硬件故障等异常情况而失真。当您需要ACID兼容功能时,您不需要重造一致性检查和崩溃恢复机制的轮子。如果您有额外的软件保护措施,超可靠硬件,或者可以容忍少量数据丢失或不一致的应用程序,您可以调整MySQL设置,以ACID的某些可靠性换取更高的性能或吞吐量。
以下部分讨论MySQL特性,特别是InnoDB存储引擎,如何与ACID模型的类别交互:
A: atomicity /ˌætəˈmɪsəti/ 原子性
C: consistency /kənˈsɪstənsi/ 一致性
I: isolation /ˌaɪsəˈleɪʃn/ 隔离性
D: durability /ˌdjʊərəˈbɪlɪti/ 持久性
1、原子性
ACID模型的原子性方面,主要涉及InnoDB事务。相关的MySQL功能包括:
1.1、autocommit设置
自动提交模式。如果设置为1,则对表的所有更改立即生效。如果设置为0,则必须使用COMMIT接受事务或ROLLBACK取消事务。如果autocommit为0,而您将其更改为1,MySQL对任何打开的事务执行自动的COMMIT。开始事务的另一种方法是使用START TRANSACTION或BEGIN语句。客户端连接时,autocommit设置为1。若要使客户端连接时autocommit默认0开始,请在服务器启动时,通过使用--autocommit=0选项,设置全局的autocommit。要使用选项文件设置autocommit变量,请参考以下行:
[mysqld]
autocommit=0
更多详情,请参考:
https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_autocommit
1.2、COMMIT声明,ROLLBACK 声明
这些陈述提供了对事务的控制使用:
START TRANSACTION 或 BEGIN 开始新的事务。
COMMIT 提交当前事务,使其更改结果持久化。
ROLLBACK 回滚当前事务,取消其更改。
SET autocommit 禁用(0)或启用(1),当前会话的默认自动提交模式。
默认情况下,MySQL运行时已开启 autocommit 模式。这意味着,当不在事务中时,每个语句是原子的,就像它被 START TRANSACTION 和 COMMIT 包围一样。不能使用ROLLBACK撤消该效果; 但是如果在语句执行期间发生错误,则回滚该语句。
如要为单个语句隐式的禁用autocommit模式,请使用START TRANSACTION语句:
START TRANSACTION;
SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summary=@A WHERE type=1;
COMMIT;
使用START TRANSACTION时,autocommit保持禁用状态,直到您使用COMMIT或ROLLBACK结束事务。自动提交模式随后恢复到其先前状态。
START TRANSACTION允许使用多个修饰符来控制事务特性。要指定多个修改器,请用逗号分隔它们。
- WITH CONSISTENT SNAPSHOT修饰符为存储引擎启动一致性读取。这仅适用于InnoDB。其效果与从任何InnoDB表发出START TRANSACTION后跟SELECT相同。WITH CONSISTENT SNAPSHOT修饰符不更改当前事务隔离级别,因此仅当当前隔离级别允许一致读取时,它才提供一致快照。唯一允许一致读取的隔离级别是REPEATABLE READ。对于所有其他隔离级别,将忽略WITH CONSISTENT SNAPSHOT子句。从MySQL 5.7.2开始,当忽略WITH CONSISTENT SNAPSHOT子句时会生成警告。
- READ WRITE和READ ONLY修饰符设置事务访问模式。它们允许或禁止对事务中使用的表进行更改。READ ONLY限制防止事务修改或锁定对其他事务可见的事务性和非事务性表;事务仍然可以修改或锁定临时表。
当事务已知为只读时,MySQL对InnoDB表上的查询进行了额外的优化。如果无法自动确定只读状态,则使用“只读”选项可确保应用这些优化。
如果未指定访问模式,则应用默认模式。除非更改了默认值,否则它是读/写的。不允许在同一语句中同时指定READ WRITE和READ ONLY。
在只读模式下,仍然可以使用DML语句更改用TEMPORARY关键字创建的表。与永久表一样,不允许使用DDL语句进行更改。
如果启用了read_only系统变量,则使用START TRANSACTION READ WRITE显式启动事务需要SUPER权限。
要显式禁用自动提交模式,请使用以下命令 声明:
SET autocommit=0;
在通过设置 autocommit变量为零, 对事务安全表的更改(例如 InnoDB或 NDB2003;,不能成为永久性 立即你必须使用COMMIT 将您的更改存储到磁盘或ROLLBACK 忽略这些变化。
更多详情,请参考:https://dev.mysql.com/doc/refman/5.7/en/commit.html
2、一致性
ACID模型的一致性方面主要涉及内部InnoDB处理,以保护数据免受崩溃。
相关的MySQL功能包括:
2.1、InnoDB双写缓冲区(doublewrite buffer)
双写缓冲区(doublewrite buffer)是一个存储区域,InnoDB在将页面数据写到适当位置的数据文件之前,会先将数据写到缓冲区中。如果在页面数据写入过程中出现操作系统、存储子系统或意外的mysqld进程退出,InnoDB可以在崩溃恢复期间,从双写缓冲区(doublewrite buffer)中找到页面的良好副本数据。
虽然数据被写入两次,双写缓冲器不需要两倍的I/O开销或两倍的I/O操作。数据以大的顺序块的形式写入双写缓冲区,只需对操作系统调用一次fsync()(除非innodb_flush_method设置为O_DIRECT_NO_FSYNC)。
在大多数情况下,双写缓冲区默认启用。要禁用双写缓冲区(doublewrite buffer),请将innodb_doublewrite设置为0。
如果Fusion-io设备上有系统数据库文件(“ibdata文件”),双写缓冲区doublewrite buffer)会自动禁用,Fusion-io原子写入用于所有数据文件。由于双写缓冲区设置是全局的,因此对于驻留在non-Fusion-io硬件上的数据文件,也会禁用双写缓冲。此功能仅在Fusion-io硬件上受支持,并且仅在Linux上为Fusion-io NVMFS启用。要充分利用此功能,建议将innodb_flush_method设置为O_DIRECT。
简要说明,InnoDB的双写缓冲(doublewrite buffer)是MySQL中的一个功能,它提供数据一致性和可靠性。它的工作过程是,在数据写入实际磁盘位置的数据文件之前,先将数据写入磁盘的一个单独部分(缓存区)。这个额外的步骤有助于防止在系统意外故障或崩溃时发生数据损坏。如果数据在写入文件时系统发生故障,InnoDB可以在系统重启时从doublewrite buffer中恢复数据,避免潜在的数据不一致或损坏。
总之,InnoDB中的双写缓冲是一种机制,通过在提交数据到磁盘之前将数据写入单独的缓冲区,确保数据的一致性和可靠性。
参考地址:
https://dev.mysql.com/doc/refman/5.7/en/innodb-doublewrite-buffer.html
2.2、InnoDB崩溃恢复(crash recovery)
InnoDB crash recovery,主题包括:
- Point-in-Time Recovery
- Recovery from Data Corruption or Disk Failure
- InnoDB Crash Recovery
- Tablespace Discovery During Crash Recovery
MySQL InnoDB 一般通过以下方式来恢复崩溃数据:
1. 通过重做日志(Redo Logs)
当数据库崩溃时,InnoDB会使用重做日志来重新执行已提交的事务,将其应用到崩溃前的状态。重做日志记录了已经完成的事务操作,可以用来重建数据库的最新状态。
2. 通过回滚日志(Rollback Logs)
回滚日志用于记录事务的undo操作,以支持事务的回滚。当数据库崩溃时,InnoDB可以使用回滚日志来撤销未完成的事务,将其恢复到崩溃前的状态。
3. 通过检查点(Checkpoints)
InnoDB定期创建检查点,将内存中的数据刷新到磁盘上的数据文件。检查点记录了哪些数据页已经持久化到磁盘,以便在数据崩溃后可以快速恢复到检查点之后的状态。
4. 通过双写缓冲(Doublewrite Buffer)
双写缓冲是InnoDB的一个特性,它在将数据写入实际数据文件之前,先将数据写入磁盘的一个单独部分。这样可以防止在写入过程中发生数据损坏,提高数据的一致性和可靠性。
参考地址:
MySQL :: MySQL 5.7 Reference Manual :: 14.19.2 InnoDB Recovery
3、隔离性
ACID模型的隔离性方面,主要涉及InnoDB事务,特别是应用于每个事务的隔离级别。相关的MySQL功能包括:
3.1、autocommit 设置
3.2、事务隔离级别和SET TRANSACTION语句
事务隔离是数据库处理的基础之一。隔离是缩写词ACID中的I;隔离级别是当多个事务同时进行更改和执行查询时,对性能和可靠性、一致性以及结果的可重复性之间的平衡进行微调的设置。
InnoDB提供了SQL-1992标准描述的所有四个事务隔离级别:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。InnoDB的默认隔离级别是REPEATABLE READ。
用户可以使用SET TRANSACTION语句更改单个会话或所有后续连接的隔离级别。要为所有连接设置服务器的默认隔离级别,请在命令行或选项文件中使用--transaction-isolation选项,详细参考:MySQL :: MySQL 5.7 Reference Manual :: 13.3.6 SET TRANSACTION Statement。
1. READ UNCOMMITTED(读未提交)
该隔离级别允许一个事务读取另一个未提交的事务所做的修改。它的主要作用是提高读取性能,但可能会导致脏读(读取到未提交的数据)。在使用场景上,READ UNCOMMITTED很少被使用,因为它的数据一致性较差,通常仅在某些特殊情况下才会考虑使用。
2. READ COMMITTED(读已提交)
该隔离级别允许一个事务只能读取已经提交的其他事务所做的修改。它解决了脏读的问题,确保读取的数据是已提交的。READ COMMITTED是MySQL默认的隔离级别。它适用于大多数应用场景,提供了较好的读取一致性和性能。
3. REPEATABLE READ(可重复读)
该隔离级别确保在同一个事务中多次读取同一数据时,结果保持一致。它通过在事务期间锁定读取的数据,避免了脏读和不可重复读的问题。REPEATABLE READ适用于需要保证数据一致性的应用场景,例如金融系统或订单处理系统。
4. SERIALIZABLE(可串行化)
该隔离级别提供了最高的数据一致性,确保并发事务之间的隔离性最大化。它通过对读取和写入的数据进行严格的锁定,避免了脏读、不可重复读和幻读的问题。SERIALIZABLE适用于对数据完整性要求非常严格的场景,但由于锁定的粒度较大,可能会影响并发性能。
参考地址:MySQL :: MySQL 5.7 Reference Manual :: 14.7.2.1 Transaction Isolation Levels
3.3、InnoDB锁的底层细节
4、持久性
ACID模型的持久性方面,涉及MySQL软件功能与特定硬件配置的交互。由于许多可能性,取决于CPU、网络和存储设备的能力,因此这方面是最复杂的。相关的功能包括:
4.1、InnoDB双写缓冲区
4.2、innodb_flush_log_at_trx_commit变量
4.3、sync_binlog变量
4.4、innodb_file_per_table变量。
4.5、存储设备(如磁盘驱动器、SSD或RAID阵列)中的写入缓冲区。
4.6、存储设备中的电池后备高速缓存。
4.7、用于运行MySQL的操作系统,特别是它对fsync()系统调用的支持。
4.8、不间断电源(UPS),用于保护所有运行MySQL服务器和存储MySQL数据的计算机服务器和存储设备的电力。
4.9、您的备份策略,例如备份的频率和类型,以及备份保留期。
4.10、对于分布式或托管的数据应用程序,MySQL服务器硬件所在的数据中心的特定特征,以及数据中心之间的网络连接。
参考地址:
https://dev.mysql.com/doc/refman/5.7/en/mysql-acid.html