数据库事务

发布于:2025-05-12 ⋅ 阅读:(28) ⋅ 点赞:(0)

事务的特性:

  • 原子性:一个事务中的所有操作要么全部完成,要么全部不完成,不会结束在中间的某个环节,而且事务在执行过程中发生错误时会回滚到事务开始前的状态。
  • 一致性:事务操作前和完成后,数据满足完整性约束,数据库保持一致性状态。示例:转账前后双方的钱总数保持一致。
  • 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,在并发环境下,一个事务内部的操作和数据对其他事务是不可见的,直到该事务提交。
  • 持久性事务完成后对数据库的修改永久性的,即时系统故障也不会丢失。

InnoDB引擎如何保证事务的四个特性?

  • 持久性:通过redo log(重做日志)
  • 原子性:通过undo log(回滚日志)
  • 隔离性:通过锁或MVCC(多版本控制并发)
  • 一致性:通过以上三种性质来保证一致

MySQL的并发相关问题:

脏读:一个事务读到了另一个事务内部还未提交的数据。

如果事务A发生了回滚,事务B读到的就是过期的数据,后续操作也可能引发错误。

不可重复读:一个事务多次读取同一行数据,由于其他事务对数据进行了修改或删除操作,出现了前后两次读到的数据不一样的情况。

幻读:同一事务内多次执行范围查询,由于其他事务的插入或删除操作,导致结果集的行数发生变化,事务读到的数据消失或者新增。

事务的隔离级别:

MySQL的默认级别是可重复读,解决了脏读和不可重复读的问题

  • 读未提交:事务未提交的数据能被其他数据读取到。
  • 读已提交:事务提交完数据后,它的数据才能被其他事务读取到。
  • 可重复读:一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的。
  • 串行化:后访问的事务必须等前一个事务执行完成,才能继续执行。

可重复读隔离级别下,A事务提交的数据,在B事务能看见吗?

不能看见,可重复读是由MVCC实现的,实现的方式是开始事务后,执行的第一个查询语句会生成一个Read View,后续的查询都基于这个Read View查询,通过Read View就可以在undo log

版本链找到事务开始时的数据,所以事务每次查询的数据都是一样的,期间其他事务提交的数据该事务是无法感知到的。

举个例子说可重复读下的幻读问题

可重复读隔离级别下虽然很大程度上避免了幻读,但是还是没有完全解决幻读

示例:事务A第一次查询时生成Read View,事务B此时提交了新的数据,事务A的修改操作恰好修改到了新的数据,此时新数据的id变成了事务A的事务id更新后的查询语句就能够查询到新数据了,此时就发生了幻读

串行化隔离级别是通过什么实现?

通过加行级锁实现,序列化隔离级别下,普通的select语句会对记录加S型的next-key锁,其他事务就没办法对这些已经加锁的记录进行增删改操作了。

MVCC实现原理

MVCC允许多个事务同时读取同一行数据,且不会彼此阻塞,每个事务看到的数据版本是该事务开始时的数据版本。这意味着如果其他事务在此期间修改了数据,正在执行的事务仍然看到的是它开始时的数据状态,从而实现了非阻塞读的状态。

对于读已提交和可重复读隔离级别的事务来说,它们是通过Read View来实现的,它们的区别在于创建ReadView的实际不同

  • 读提交:是在每个select语句执行前都会重新生成一个ReadView
  • 可重复读:执行第一条select时,生成一个Read View,然后整个事务期间都在用这个Read View


 


网站公告

今日签到

点亮在社区的每一天
去签到