MySQL事务和锁

本文详细探讨了MySQL中的事务,包括事务的ACID属性、并发事务可能导致的问题以及事务隔离级别。接着,介绍了锁的分类,如表锁和行锁,并深入讲解了行锁的不同类型。文章还通过实例分析了不同事务隔离级别下的行锁行为,以及锁的优化建议,旨在帮助读者理解MySQL如何处理并发事务和数据一致性。
摘要由CSDN通过智能技术生成

作者:IT王小二

博客:https://itwxe.com

MySQL是怎么解决并发事务所产生的问题呢?又借助了哪些锁的思想呢?这篇小二给小伙伴们继续唠一唠MySQL的那些事。

一、事务是什么

事务是由一组SQL语句组成的逻辑处理单元,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。通常有下面4个特性,也就是咱程序猿俗称的ACID属性。

  • 原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全部执行,要么全部不执行。举个例子:情人节小二给女朋友转账520块,那么SQL中一共两个操作,小二的账户余额-520块,女朋友账户余额+520块,这一组转账操作,不能只执行小二的账户-520块,或者只执行女朋友账户余额+520块,只能都执行,或者都不执行。
  • 一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。一致性和原子性息息相关,即一组转账操作下来小二账户余额应该-520块,女朋友账户余额+520块,两人转账操作之后账户总金额是一致的。
  • 隔离性(Isolation):一个事务的执行不能被其他事务干扰,即每个事务都是独立的,不受其他事务的影响。简单来说就是一个事务(T1)处理过程的中间状态对其他事务(T2, T3…)是不可见的;同理,T2同样对T1和T3的中间状态不可见的。即只要小二的转账操作没完成,那么女朋友不管怎么查询结果都是原来的余额,而不会查询多出520块。
  • 持久性(Durable):事务完成之后,对数据的修改是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。即只要小二转账成功了,数据就保存磁盘了。

二、并发事务所产生的问题

脏写或者更新丢失(Lost Update)

当两个或多个事务同一时间修改同一行,然后基于最初选定的值进行业务操作更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题。

简单来说就是最后的更新覆盖了由其他事务所做的更新

脏读(Dirty Reads)

一个事务读到了其他事务已经修改但是未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不一定会存到数据库中,所以读出来的数据是无效的。

不可重复读(Non-Repeatable Reads)

一个事务在读取某些数据后的某个时间点,再次读取以前读过的那批数据,却发现其读出的数据已经发生了改变,可能会受到其他事务的影响,比如其他事务改了这批数据并提交了。通常针对数据更新(UPDATE)操作或者删除(DELETE)操作。

简单来说就是在一个事务中,相同查询语句在不同时刻查询出来的结果不一致,可能是结果字段值不一致,也可能是少了行数据

幻读(Phantom Reads)

对比不可重复读,幻读是针对数据新增(INSERT)来说的,在同一事务下,在读取某些数据后的某个时间点,再次读取以前读过的那批数据,第二次的SQL语句返回了之前不存在的行

简单来说就是事务A读取到了其他事务提交的新增数据

再来区分一下经常搞混的不可重复读幻读

  • 不可重复读:说的是原来存在的记录A,记录A从A变成了记录B。
  • 幻读:出现了原来不存在的记录。

当然还是区分不明显的小伙伴可以结合五、行锁与事务隔离级别案例分析理解理解,理论结合实践,nice~

三、事务隔离级别

并发事务产生的脏读、不可重复读、幻读都是数据库读取的一致性,问题,所以数据库提供了一定的事务隔离级别来解决产生的问题。

隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

MySQL数据库默认的隔离级别为可重复读(repeatable-read),也就是我们常说的RR级别。

查看事务隔离级别:show variables like 'tx_isolation';

设置事务隔离级别,例如设置隔离级别为读未提交:

  • 仅对当前会话生效,立即生效:set session transaction isolation level read uncommitted;或者set tx_isolation = 'read-uncommitted';
  • 对全局会话生效,需要退出会话后生效:set global transaction isolation level read uncommitted;

用Spring开发程序时,如果不设置隔离级别默认用MySQL设置的隔离级别,如果Spring设置了就用设置的隔离级别。

四、锁分类

锁是计算机协调多个进程或者线程并发访问同一资源的机制,而对于数据库来说数据就是一种需要用户共享的资源,怎么保证数据的并发访问一致性和高效性是数据库需要解决的问题。

按不同分类有以下分类。

  • 从性能上来分,分为乐观锁和悲观锁
    • 乐观锁比较乐观,乐观锁假设数据一般情况不会造成冲突,多线程同时对同一行数据修改的时候,在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。
    • 悲观锁比较悲观,多线程同时对同一行数据修改的时候,最终只有一个线程修改成功。
  • 从对数据库操作的类型分,分为读锁和写锁(都属于悲观锁)。
    • 读锁(共享锁,S锁(Shared)):针对同一份数据,多个读操作可以同时进行而不会互相影响。
    • 写锁(排它锁,X锁(eXclusive)):当前写操作没有完成前,它会阻断其他写锁和读锁。
  • 从对数据操作的粒度分,分为表锁和行锁

1. 表锁

每次操作锁住整张表。开销小,加锁快,不会出现死锁,锁定粒度大,发生锁冲突的概率最高,并发度最低,一般用在整表数据迁移的场景。

基本操作

  • 手动增加表锁:lock table 表名称 read/write,表名称2 read/write;
  • 查看表上加过的锁:show open tables;
  • 删除表锁:unlock tables;

实操一下

-- 创建示例表
CREATE TABLE `test_myisam_lock` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE = MyISAM DEFAULT CHARSET = utf8;

-- 插入几条数据
INSERT INTO `blog_test`.`test_myisam_lock` (`id`, `name`, `age`) VALUES (1, 'itwxe', 18);
INSERT INTO `blog_test`.`test_myisam_lock` (`id`, `name`, `age`) VALUES (2, 
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值