mysql的锁和事务

news/2024/5/20 20:48:53
mysql的锁
  • 读写锁:
    • 读锁是共享锁,多个用户在同一时刻可以读取同一资源,相互不受干扰
    • 写锁是排他锁,写锁会阻塞其他的写锁和读锁,这样可以确保在指定的时间内,只有一个用户可以写入
  • 锁的颗粒度:
    • 想要提高并发性,就需要尽可能的只锁住需要修改的资源,而不是所有资源
    • 同时加锁也需要消耗资源,锁的各种操作都会增加系统的开销,影响系统的性能
    • 所以锁的策略就是在锁的开销和数据安全性之间寻找平衡
    • MySQL提供了多种选择,每种存储引擎都可以实现自己的锁策略和锁粒度,针对不同场景有不同的解决方案
      • 表锁
        • 表锁是mysql最基本的锁策略,它的开销最小,但他会锁定整张表,想要进行写操作,必须先获取写锁,这会阻塞其他用户对表的读写操作
        • 虽然存储引擎有自己的锁策略,但是例如 Alter table 这种操作仍然是表锁,会忽略存储引擎的锁机制
      • 行级锁
        • 行级锁可以最大程度的支持并发处理,但同时也带来了最大的锁开销
        • 行级锁只在存储引擎层实现,mysql服务层没有实现
      • mvcc(多版本并发控制)
        • 可以认为是行级锁的变种,在很多情况下可以避免加锁,开销更低
        • innodb的MVCC,是通过每行记录保存两个隐藏的列来实现的,一个是行的创建版本号,一个是删除版本号,每开始一个新的事务,版本号都会自动递增

mysql的死锁:

  • 当多个事务试图以不同的顺序锁定资源时,就有可能产生死锁,多个事务同时锁定一个资源时也有可能产生死锁
  • 例如A事务先更新第一行数据,在更新第二行数据,B事务先更新第二行数据,在更新第一行数据,这样就会导致两个事务都在等待对方释放锁,同时又持有对方需要的锁,陷入死循环
  • 为了解决这种问题,数据库实现了各种死锁检查和超时机制,innodb目前处理死锁的方法是,将持有最少行级排他锁的事务回滚
  • 死锁一旦发生,只有部分或者完全回滚其中一个事务,才能打破死锁,对于事务型的系统,这是无法避免的,所以需要在程序设计时考虑如何避免死锁
mysql事务

事务的基本要素:ACID事务:

  • 原子性:事务是一个不可分割的单位,事务中的操作要么都发生,要么都不发生
  • 一致性:事务前后数据的完整性必须保持一致,方便回滚
  • 隔离性:事务与事务之间的操作不能相互干扰
  • 持久性:一个事务一旦被提交,它对数据库中数据的改变就是永久的,即使接下来数据库发生故障,也不应该对其有任何影响

事务日志:

  • 事务日志可以提高事务效率,使用事务日志,存储引擎在修改表的数据的时候,只需要修改内存拷贝,再把修改行为持久化到硬盘上的事务日志,

  • 内存中的数据在后台可以慢慢的刷回磁盘,不用每次都将修改的数据本身持久化到磁盘,也就是修改数据其实需要写两次磁盘

  • 事务日志采用的是追加的方式,是顺序I/O

mysql中的事务:

  • mysql默认采用自动提交,也就是说如果不是显示的指定一个事务的开始,每次操作都会被当成一个事务执行提交操作
  • mysql可以识别4个隔离级别,innodb也支持所有的隔离级别
  • 事务是由存储引擎实现的,所以在同一个事务中,使用多种存储引擎是不可靠的
    • 例如在事务中混用了事务型表和非事务型表,如果回滚非事务型表也无法撤销,会导致数据的不一致,这种情况很难修复,事务的最终结果也无法确定
  • 锁也分为显示和隐式,存储引擎自己加的锁,都是隐式的,当然也可以自己显示的加锁,但是这样不仅没有必要,还会影响性能

事务的隔离级别

  • 读未提交

    • 如果一个事务开始了写操作,虽然不允许其他事务同时进行写操作,但允许其他事务读取数据,有可能出现脏读,也就是读取到了其他事务未提交的数据。
  • 读已提交

    • 对于一行数据,如果有一个写事务将会禁止其他事务访问该行数据,避免了脏读,但是可能出现不可重复读,
    • 也就是事务A事先读取了数据,事务B紧接着更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。
  • 可重复读

    • 可重复读取是指在一个事务内,多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据,这样避免了不可重复读和脏读,但是有时可能会出现幻读。
    • 也就是一个事务在前后两次查询同一个范围的时候,因为只是禁止事务对查询到的数据进行操作,并不能禁止其他事务插入新的数据,所以后一次查询会看到了前一次查询没有看到的行
    • mysql还额外增加了范围锁,避免了幻读问题
  • 串行化

    • 要求事务序列化执行,事务只能一个接着一个地执行
    • 序列化是最高的事务隔离级别,同时代价也是最高的,性能很低,一般很少使用,在该级别下,事务顺序执行,可以避免脏读、不可重复读以及幻读。
  • MySQL默认隔离级别为:可重复读 (Repeated read),Oracle默认隔离级别为:读已提交(READ COMMITTED)


https://www.xjx100.cn/news/3.html

相关文章

【C++之容器篇】精华:vector常见函数的接口的熟悉与使用

目录前言一、认识vector1. 介绍2. 成员类型二、默认成员函数(Member functions)1. 构造函数2. 拷贝构造函数vector (const vector& x);3. 析构函数4. 赋值运算符重载函数三、迭代器(Iterators)1. 普通对象的迭代器2. const对象…