在做项目的时候难免会有并发操作,这时候就不得不引出Mysql 的事务了,但是我们一直常说的acid事务的四大特性,究竟是如何实现的呢,这不仅让我思考,于是我找到了黑马程序员的mysql讲解。
事务的基本概念
事务是一个不可分割的工作逻辑单元,由一系列数据库操作组成。这些操作要么全部成功执行,要么全部失败回滚。例如,在一个银行转账场景中,从账户 A 向账户 B 转账 100 元,这个过程涉及两个操作:从账户 A 扣除 100 元,向账户 B 增加 100 元。这两个操作必须作为一个事务来处理,以保证转账的正常进行。如果只执行了扣除操作而增加操作失败,那么就会导致数据不一致。
事务的 ACID 特性
原子性(Atomicity)
原子性确保事务中的所有操作要么全部成功提交,要么全部回滚。就像上述银行转账例子,从账户 A 扣除和向账户 B 增加这两个操作,要么都完成,要么都不完成,不存在只完成其中一个操作的情况。在 MySQL 中,通过日志机制来实现原子性,例如重做日志(redo log)和回滚日志(undo log)。当事务执行过程中发生错误时,MySQL 可以根据回滚日志撤销已经执行的操作,保证事务的原子性。
一致性(Consistency)
一致性要求事务执行前后,数据库的完整性约束不被破坏。
隔离性(Isolation)
事务的隔离性指的是,在多个并发事务对同一个数据进行操作时,每一个事务都处于一个互不干扰的独立环境当中
- 读未提交(Read Uncommitted):最低的隔离级别,一个事务可以读取到另一个未提交事务的数据。这种级别存在脏读问题,即读取到了可能会回滚的数据。
- 读已提交(Read Committed):一个事务只能读取到已经提交事务的数据。避免了脏读,但可能会出现不可重复读问题,即同一事务内多次读取同一数据时,由于其他事务的修改,导致读取结果不一致。
- 可重复读(Repeatable Read):MySQL 的默认隔离级别。在同一事务内多次读取同一数据时,结果始终保持一致,即使其他事务在期间对该数据进行了修改并提交。但可能会出现幻读问题,即当事务 A 按一定条件查询数据时,事务 B 插入了满足该条件的新数据,事务 A 再次查询时会发现多了一些原本不存在的数据。
- 串行化(Serializable):最高的隔离级别,所有事务依次执行,避免了脏读、不可重复读和幻读问题,但并发性能较低。
持久性(Durability)
持久性保证一旦事务提交,其所做的修改会永久保存在数据库中,即使系统崩溃或发生其他故障。
事务的实现机制
日志
- 重做日志(redo log):用于记录事务对数据页的物理修改操作。当事务提交时,MySQL 会将事务的重做日志写入磁盘。在系统崩溃后重启时,MySQL 可以通过重做日志来恢复尚未持久化到磁盘的数据,保证已提交事务的持久性。
- 回滚日志(undo log):用于记录事务对数据的修改前状态。在事务执行过程中,如果需要回滚,MySQL 可以根据回滚日志将数据恢复到事务开始前的状态,从而保证事务的原子性。
锁机制
在并发环境下,为了保证事务的隔离性,MySQL 使用了锁机制。例如,当一个事务对某条数据进行修改时,会给该数据加上排他锁(X 锁),防止其他事务同时对该数据进行修改。而在读取数据时,可能会根据隔离级别加上共享锁(S 锁),以保证在同一事务内多次读取数据的一致性。不同的隔离级别下,锁的使用策略也有所不同。例如,在可重复读隔离级别下,MySQL 通过 MVCC(多版本并发控制)机制和适当的锁机制相结合,来提高并发性能的同时保证事务的隔离性。
mvcc
隐藏字段分为三种:DB_TRX_ID(当前事务ID), DB_ROLLPTR(用于指定undolog的对应记录,数值即上一次进行数据更改操作所记录的数据对应的undolog的指针) , DB_ROW_ID(该表没有主键的时候会自动生成)
总结
理解这些原理对于开发者编写高效、可靠的数据库应用至关重要。通过合理地运用事务,能够确保数据的一致性和完整性,提升系统的稳定性和可靠性。在实际开发中,我们需要根据具体的业务需求,选择合适的事务隔离级别和锁策略,以平衡系统的并发性能和数据一致性要求。希望本文对大家理解 MySQL 事务原理有所帮助,为进一步深入学习数据库开发打下坚实的基础。