跳到主要内容

数据库相关

数据库的隔离级别

没有足够时间去研究和实践,看完还是乱七八糟的,面试场景应该是够了。

以前没怎么详细关注,一直以为默认配置到“可重复读”就没有什么所谓的脏读幻读杂七杂八的问题了,没想到据说还是会有“幻读”问题。

  • 脏读是读取到其他transaction事务未提交的数据,配置“读取已提交”就可以解决
  • 幻读 phantom 是批量读取的场景里,读取到其他transaction新增的记录。 一般配置“可重复读”之后,读取同一条记录就没有所谓的幻读问题。不过对于其他transaction新增提交的记录,在select count(1)的场景里据说还是能被识别到。

数据库的隔离级别,通过配置可以完成:

  • 读取未提交(Read Uncommitted): 会出现各种混乱
  • 读取已提交(Read Committed): 某条记录如果被其他trancation修改提交了,本transaction就能读取到这条记录。
  • 可重复读(Repeatable Read): 一般默认就是这样,用mvcc版本标记更简单
  • 序列化读(Serializable):大家一起排队慢慢来

还有select 语句里的也能直接带上锁,比如 select for update, select for share/delete/insert。 代表当前select的这行数据加上不同种类的行级锁,本质上就是加上悲观锁, 在使用mvcc版本乐观锁 + 可重复读后日常使用里就很少见了。 select for update 这些叫做“当前读“, mvcc这些叫做”快照读“,又是一个没怎么接触过的名词。

咨询chatgpt的结果

  • SELECT LOCK IN SHARE MODE:这是一个行级别的共享锁语句。当在一个事务中执行带有 LOCK IN SHARE MODE 子句的查询时,查询结果中的行将被共享锁定。其他事务可以读取这些行,但无法对它们进行修改,直到持有共享锁的事务释放锁或提交事务。

  • SELECT FOR UPDATE:这是一个行级别的排他锁语句。当在一个事务中执行带有 FOR UPDATE 子句的查询时,查询结果中的行将被排他锁定。其他事务无法读取或修改这些行,直到持有排他锁的事务释放锁或提交事务。

其他地方摘录到的,算是比较靠谱的了

1.解决不可重复读,MySQL改下隔离级别到“可重复读” 2.解决幻读,MVCC处理不了幻读问题,可以加锁解决,select ... for update

摘录与参考文档

MySQL 可重复读隔离级别,完全解决幻读了吗? https://www.xiaolincoding.com/mysql/transaction/phantom.html

MySQL InnoDB 引擎的可重复读隔离级别(默认隔离级),根据不同的查询方式,分别提出了避免幻读的方案:

  • 针对快照读(普通 select 语句),是通过 MVCC 方式解决了幻读。
  • 针对当前读(select ... for update 等语句),是通过 next-key lock(记录锁+间隙锁)方式解决了幻读。

MySQL 可重复读隔离级别并没有彻底解决幻读,只是很大程度上避免了幻读现象的发生。要避免这类特殊场景下发生幻读的现象的话,就是尽量在开启事务之后,马上执行 select ... for update 这类当前读的语句,因为它会对记录加 next-key lock,从而避免其他事务插入一条新记录。

MySQL - MySQL InnoDB的MVCC实现机制 https://pdai.tech/md/db/sql-mysql/sql-mysql-mvcc.html

准确的说,MVCC多版本并发控制指的是 “维持一个数据的多个版本,使得读写操作没有冲突” 这么一个概念。仅仅是一个理想概念而在MySQL中,实现这么一个MVCC理想概念,我们就需要MySQL提供具体的功能去实现它,而快照读就是MySQL为我们实现MVCC理想模型的其中一个具体非阻塞读功能。而相对而言,当前读就是悲观锁的具体功能实现

多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。 所以MVCC可以为数据库解决以下问题在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能, 同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题。

created at 2024-02-21