贵金属行情
微信公众号

MySQL之并发控制和事务

引言

原文链接:http://yunsonbai.top/2020/09/07/mysql-bfsw/
整理了一下之前学习MySQL的知识点–并发控制和事务,和大家分享。

并发控制

无论什么时候,只要有多个线程(或进程)同一数据修改数据,就会产生并发控制问题

读写锁

共享锁和排他锁(或者是读锁和写锁)

  • 读锁: 共享的,多用户可以同时读取同一个资源,相互不干扰
  • 写锁: 排他,会阻塞其他的读锁或者写锁,只能一个用户写入

锁粒度

尽量只锁住需要修改的内容,而不是所有资源。任何时候,在给定的资源上,锁的数量越少,冲突越少,那么系统的并发程度就越高。

锁也耗资源,锁的操作包括,检查所是否已经解除,获得锁,释放锁,这些都会增加系统开销,进而影响系统性能。锁策略,就是在锁的开销和安全性之间寻求平衡。一般会采用行级锁,MySQL提供了多个选择,每种存储引擎都能实现自己的锁

表锁

MySQL中最基本的锁策略,开销最小,粗暴简单。锁住整张表,需要拿到该锁才能进行增改删,而且该锁还会阻塞其他用户的读。只有没有写锁时,多用户才能同时读取。

另外MySQL会在使用alert table之类的语句中使用表锁,忽略存储引擎自己的锁

行级锁

行级锁能最大程度的支持并发处理,但是也带来了最大的锁开销。在InnoDB中实现了行级锁。

事务

在MySQL中,MySQL服务器不管理事务,由下层的存储引擎实现。因此混合使用存储引擎是不可靠的。
MySQL默认采用自动提交,如果不是显式的开始一个事务的话,则每个查询都被当做一个事务执行提交操作。

事务就是一组原子行的sql查询,独立的工作单元。
一个事务中,要么所有的语句都成功,如果有n条失败,那全部失败,都不执行。

事务特性包括

  • 原子性:单元操作,都成或所有都不成(有一个失败就全失败)
  • 隔离性:事务之间相互隔离。
  • 持久性:改完得保存起来,不能丢。
  • 一致性:得保证最终状态一致。

隔离级别

未提交读

事务中的修改,即使没有提交,对其他事务可见。其他事务就产生了脏读,这样就会产生很多问题。

提交读

大多数数据库默认的隔离级别。一个事务开始时,只能看见已提交的事务所做的修改。也就是说一个事务从开始到未提交之前,其他事务都是 不可见的。也可以叫不可重复读,因为两次同样的查询可能得到不一样的结果。

可重复读

保证了在同事务中多次读取同样的记录结果是一样的。但理论上还是会有幻读的情况,当某个事务读取某个范围内的记录时,另一个事务又在该范围内插入了新的记录,当前的事务再次读取该范围的数据时,会产生幻行。
可重复读是MySQL的默认事务隔离级别,后边的过版本控制协助MySQL完成可重复读。

可串行化

强制保证事务串行执行,避免了前面说的幻读问题。但会导致大量的超时和锁竞争,这种隔离级别在实际中很少用到。

死锁

两个及以上事务相互占用对方的资源,导致死锁。解开的方式是只能一个事务成功,其他事务全部回滚。

事务A: 1、更新a 2、更新b
事务B: 1、更新b 2、更新a
恰好两个事务都执行了1,都要到了执行2,那相互之间就产生了死锁。

多版本并发控制

采用多版本来控制并发,进而实现可重复读。
通过保存数据在某个时间点的快照来实现,每开始一个新的事物,系统版本号都会自动递增。

在InnoDB中:

  • 查找:

    • 只查找系统版本号小于或等于事物的系统版本号。可确保读取的行,要么是在事务开始前就有,要么是在本事务中插入或修改的过的。

    • 行的删除版本要么未定义,要么大于当前事务版本号。确保读取的行,在事务开始前未被删除。

  • 插入: 为新插入的每一行保存当前系统版本号作为行版本号

  • 删除: 为删除的每一行保存系统版本号作为行删除的标识
  • 更新: 为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来行作为行删除标识。
yunsonbai wechat
微信公众号