MySQL事务的四大特性以及事务的隔离级别

本文详细介绍了数据库事务的四大特性——原子性、一致性、隔离性和持久性,并重点解析了事务的隔离级别,包括读未提交、读已提交、可重复读和串行化。在MySQL中,可重复读是默认隔离级别,通过MVCC机制实现。文章还讨论了MVCC如何保证事务在读取数据时的快照一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、事务的四大特性(ACID)

如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性:

1、原子性(Atomicity)

  原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

2、一致性(Consistency)

  一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
  拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

3、隔离性(Isolation)

  隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
  即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

4、持久性(Durability)

  持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
  例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,
即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

二、事物隔离级别

读未提交

 read uncommitted,就是某个事物还没提交的时候,修改的数据,让别的事务读到了。这个也叫脏读                             

读未提交
读未提交

读已提交

read committed,事务A在跑的时候,先查询了一个数据是值1,然后过了段时间,事务B把那个数据给修改了一下还提交了,此时事务A再次查询这个数据就成了值2了,这是读了人家事务提交的数据,所以是读已提交。也叫不可重复读,就是所谓的一个事务内对一个数据两次读,可能会读到不一样的值。

                                      

读已提交

 

 可重复读

Read Repeatable,事务A在执行过程中,对某个数据的值,无论读多少次都是1,哪怕这个过程中事务B修改了数据的值还提交了,但是事务A读到还是自己事务开始时这个数据的值。                                    

可重复读

幻读

不可重复读和可重复读都是针对两个事务同时对某条数据在修改,但是幻读针对的是插入,比如某个事务把所有行的某个字段都修改为了2,结果另外一个事务插入了一条数据,那个字段的值是1,这时第一个事务突然发现多出来一条数据,那个数组字段是1。如果解决幻读,就需要使用串行化级别的隔离级别,所有事务都串行起来,不允许多个事务并行操作

幻读

 

串行化

 

mysql 默认的隔离级别是read repeatable,可重复读,就是说每个事务都会开启一个自己操作的某个数据快照,事务期间,读到的都是这个数据的快照。

mysql 是如何实现 read repeatabled的,是通过MVCC机制来实现的,就是多版本并发控制

innodb存储引擎会在每行数据的最后加两个隐藏列,一个保存行的创建时间,一个保存行的删除时间,但是这存放的不是时间,而是事务id,事务id 是mysql 自己维护的,全局唯一递增的

id     name    创建事务id    删除事务id

1      张三      120               空(122)

2      李四      119               空

2     小李四    122              空

事务id = 121的事务,查询 id = 1的这一行时候,一定会找到创建事务id <=当前事务id的那一行,select * from table where id = 1,就可以查到上面那一行

事务id = 122 的事务,将id = 1这行数据删除,此时就会将 id = 1的行的删除事务id 设置成 122

事务id = 121 的事务,再次查询id = 1的那一行,能查到吗?能查到,要求创建事务id < = 当前事务id,当前事务id< 删除事务id

事务id =121的事务,查询id = 2 那行,查到name = 李四

事务id = 122 的事务,将id = 2 那行,更新name = 小李四,修改不是在原来数据上修改,而是新增一条数据

事务id = 121的事务,查询id = 2的那行,答案 肯定是 :李四

在一个事务内查询的时候,mysql只会查询创建时间的事务id小于等于当前事务id的行,这样可以确保这个行是在当前事务中创建,或者是之前创建的;同时一个行的删除时间的事务id要么没有定义(就是没删除),要么肯定比当前事务id大(在事务开启之后才删除)满足这两个条件的数据都会被查出来。

那么如果某个事务执行期间,别的事务更新了一条数据呢,其实就是在innodb中,是插入了一行记录,然后将新插入的记录的创建时间设置为新的事务id,同时将这条记录之前的那个版本的删除时间设置为新的事务的id。

这样的话,事务对某行记录的查询,始终都是查找的之前的快照,因为之前的那个快照的创建时间小于等于自己事务id,然后删除时间的事务id 比自己事务id大,所以这个事务运行期间,会一直读取到这条数据的同一个版本。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值