mysql事务机制(事务的四个隔离级别如何实现?),读完会深入理解很多

58 阅读5分钟

事务的acid

原子性:事务不可再分割,多条语句要么都成功,要么都失败。 一致性:事务执行的前后数据要保持一致 隔离性:并发访问数据库时, 事务的执行不能对别的事务产生影响 持久性:事务修改删除数据一定是持久的,即使数据库发生故障也不应该有任何影响

事务的隔离级别

读未提交:读取到事务还没有提交的数据。会有脏读的问题。

读已提交:读取到事务已经提交的数据。会有不可重复读的问题。会读取到别人已经修改的数据,假如别人短时间修改了多次就会有每次读取数据不一样。有读取时间节点不一样的问题,不能保证时间的一致性。

可重复读:可以避免不可重复读,脏读的问题,就是可以避免读取到别的事务已经修改的数据。但是会有幻读的问题(读取到别的事务已经插入或者删除的数据)

串行化:一个执行完之前别的线程才能执行,可以避免脏读,不可重复读,以及幻读的问题。

串行化的实现方式:

如果是读操作的话就是在后台加了一个读锁,别的可以读,但是不能修改。

如果是写操作就加一个写操作。别的不能读,不能写。

不可重复读实现的方式:

快照读取。在执行链中读取当前事务已提交的一条数据,后面事务再提交的数据都不再读取。所以就会出现读取了当前数据,就算别的事务再更改之后,当前事务查出来依旧是老的数据。

mvcc的思想

mvcc:执行链,undo回滚日志,回滚回滚指针roll_pointer.

copyOrWrite机制:

是一种思想:在更新的时候去更新副本,更新完成之后,直接替换原来旧的。

在微服务组件nacos当要去更新配置文件的时候就会用到cow

为什么要这样用呢,为什么不直接在nacos更新的时候加一个锁,然后就可以了呢?

因为加锁就会串行化,然后就会导致效率降低。

读已提交实现方式:

读取的是版本链里面最后一条数据,所以读取的是已经提交的数据。

读未提交就是读取的执行链路中还没有提交的数据。

,最后就会使用copyorwriter.先把副本写好,再替换掉。

不可重复度会出现的问题:

当快照读取值为500的数据之后,就会用500的值取操作,但是当500的值在事务的期间发生了值得改变就会有问题。

解决办法就是加一个乐观锁(跟新的时候加上版本号),如果在事务期间发生问题就回滚,没有发生就不回滚。

还有一个办法就是在修改的时加一个悲观锁。这行就会锁定住,锁定的时候查询的数据就不是一个快照读,而是一个当前已提交的读取。

查询需要用事务码?

分情况:查询单条语句不需要用事务。但是如果是没有事务的情况下的话,如果是查询多条sql语句,第一条读取的时间节点和第二条查询的时间节点不一样,如果第一条查询出来之后,第二条被更改了,再查询出来,加了事务和不加这两个查询结果不一样。但是如果是可重复读就可以避免被更改的问题了。

如果是读已提交查询出来的就是不同时间的数据了。没有课重复度的一致性好。默认用的课重复读。

什么情况应该用什么事务?

做erp的公司用可重复读的一致性会高一点,对并发要求又不高,因为读取的数据会是一个当前同一时间点的数据。

如果是用的读已提交,他读取的数据很可能不会是同一时间节点的数据。

大量并发过来的时候为什么最好用读已提交,因为如果使用可重复度,就会读取到当前数据,进行快照。修改的时候可能会有很多并发来修改,就会回滚事务,大量回滚事务就会造成问题的报错。

mysql的持久化方式:

1.首先innodb会去ibd磁盘文件中读取数据到bufferpoll中,

2.然后会再undolog里面取记录信息,方便回滚,然后就是

3.执行器会更新内存数据

4.执行器会在存储引擎的redolog日志取写日志,然后日志会写入redo日志中,写入redo日志用的是一个顺序写速度非常的快。比后面写道磁盘里面的随机写快得多。当发生宕机得时候,只要redo日志里面有数据就会把日志读取出来放到持久化硬盘里面去。

5.准备提交事务binlog日志将会写入磁盘里去。,然后写入redo里面去

6.buff pool里面会有一个缓存池有一个异步线程会用随机写的方式持久化到磁盘上面去。

为什么用随机写,因为用不了顺序写,因为多个表不同的操作就不是顺序写,而且删除掉一个数据顺序就不对了。不适合顺序写。