『MySQL 实战 45 讲』15 - 两阶段提交、索引相关问题

news2024/10/6 16:04:50

日志和索引相关问题

mysql 两阶段提交问题

在这里插入图片描述

  1. 在两阶段提交的不同时刻,MySQL 异常重启会出现什么现象?
  • 如果 crash 发生在时刻 A
    • 由于此时 binlog 还没写,redo log 也还没提交,所以崩溃恢复的时候,这个事务会回滚
  • 如果 crash 发生在时刻 B【主要】
    • 如果 redo log 里面的事务是完整的,也就是已经有了 commit 标识,则直接提交
    • 如果 redo log 里面的事务只有完整的 prepare,则判断对应的事务 binlog 是否存在并完整
      • 如果是,则提交事务
      • 否则,回滚事务
  1. MySQL 怎么知道 binlog 是完整的?
  • statement 格式的 binlog,最后会有 COMMIT
  • row 格式的 binlog,最后会有一个 XID even
  • MySQL 5.6.2 版本以后,还引入了 binlog-checksum 参数,用来验证 binlog 内容的正确性
  1. redo log 和 binlog 是怎么关联起来的?
  • 有一个共同的数据字段 XID,崩溃恢复的时候,会按顺序扫描 redo log
    • 既有 prepare、又有 commit 的 redo log,就直接提交
    • 只有 parepare、而没有 commit 的 redo log,就拿着 XID 去 binlog 找对应的事务
  1. 处于 prepare 阶段的 redo log 加上完整 binlog,重启就能恢复,MySQL 为什么要这么设计?
  • 数据与备份的一致性有关。采用这个策略,主库和备库的数据就保证了一致性
  1. 能不能只用 redo log,不要 binlog?
  • 理论上可以,把 binlog 关掉,这样就没有两阶段提交了,但系统依然是 crash-safe 的
  • 但 binlog 作用是归档,而 redo log 是循环写,起不到归档作用
  1. redo log 一般设置多大?
  • 对于几个 TB 的磁盘,设置为 4 个文件、每个文件 1GB
  1. 正常运行中的实例,数据写入后的最终落盘,是从 redo log 更新过来的还是从 buffer pool 更新过来的呢?
  • 如果是正常运行的实例的话,数据页被修改以后,跟磁盘的数据页不一致,称为脏页。最终数据落盘,就是把内存中的数据页写盘。这个过程,甚至与 redo log 毫无关系
  • 在 crash 场景下,InnoDB 如果判断到一个数据页可能在崩溃恢复的时候丢失了更新,就会将它读到内存,然后让 redo log 更新内存内容。更新完成后,内存页变成脏页,就回到了第一种情况的状态
  1. redo log buffer 是什么?是先修改内存,还是先写 redo log 文件?
  • 例子:
begin;
insert into t1 ...
insert into t2 ...
commit;
  • 在执行第一个 insert 的时候,数据的内存被修改了,redo log buffer 也写入了日志
  • 真正把日志写到 redo log 文件(文件名是 ib_logfile+ 数字),是在执行 commit 语句的时候做的

业务设计问题

  1. 业务需求如下
A、B 两个用户,如果互相关注,则成为好友。
设计上是有两张表,一个是 like 表,一个是 friend 表,like 表有 user_id、liker_id 两个字段
我设置为复合唯一索引即 uk_user_id_liker_id

以 A 关注 B 为例:
第一步,先查询对方有没有关注自己(B 有没有关注 A)
select * from like where user_id = B and liker_id = A;

如果有,则成为好友
insert into friend;

没有,则只是单向关注关系
insert into like;

但是如果 A、B 同时关注对方,会出现不会成为好友的情况。
因为上面第 1 步,双方都没关注对方。
第 1 步即使使用了排他锁也不行,因为记录不存在,行锁无法生效。
请问这种情况,在 MySQL 锁层面有没有办法处理?
  1. sql 模板设计大概这样
CREATE TABLE `like` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `liker_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_user_id_liker_id` (`user_id`,`liker_id`)
) ENGINE=InnoDB;

CREATE TABLE `friend` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `friend_1_id` int(11) NOT NULL,
  `friend_2_id` int(11) NOT NULL,
  UNIQUE KEY `uk_friend` (`friend_1_id`,`friend_2_id`),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
  1. 出现业务 bug 的时序
  • 第 1 步即使使用了排他锁也不行,因为记录不存在,行锁无法生效
    在这里插入图片描述
  1. 解决方案
  • 给 “like” 表增加一个字段,比如叫作 relation_ship,并设为整型,取值 1、2、3
    • 1:表示 user_id 关注 liker_id
    • 2:表示 liker_id 关注 user_id
    • 3:表示互相关注
  • 在应用代码里面比较 A 和 B 的大小
    • 如果 A < B,执行下面逻辑
    mysql> begin; /*启动事务*/
    insert into `like`(user_id, liker_id, relation_ship) values(A, B, 1) 
    on duplicate key update relation_ship=relation_ship | 1;
    
    select relation_ship from `like` where user_id=A and liker_id=B;
    /*
    代码中判断返回的 relation_ship, 
    如果是1,事务结束,执行 commit 
    如果是3,则执行下面这两个语句: 
    */
    insert ignore into friend(friend_1_id, friend_2_id) values(A,B);
    commit;
    
    • 如果 A > B,则执行下面的逻辑
    mysql> begin; /*启动事务*/
    insert into `like`(user_id, liker_id, relation_ship) values(B, A, 2) 
    on duplicate key update relation_ship=relation_ship | 2;
    
    select relation_ship from `like` where user_id=B and liker_id=A;
    /*
    代码中判断返回的 relation_ship,
      如果是2,事务结束,执行 commit
      如果是3,则执行下面这两个语句:
    */
    insert ignore into friend(friend_1_id, friend_2_id) values(B,A);
    commit;
    
  • “like” 表里的数据保证 user_id < liker_id,这样不论是 A 关注 B,还是 B 关注 A,在操作 “like” 表的时候,如果反向的关系已经存在,就会出现行锁冲突
  • insert … on duplicate 语句(这个语句只有 mysql 里有),确保了在事务内部,执行了这个 SQL 语句后,就强行占住了这个行锁,之后的 select 判断 relation_ship 这个逻辑时就确保了是在行锁保护下的读操作
  • 操作符 “|” 是按位或,连同最后一句 insert 语句里的 ignore,是为了保证重复调用时的幂等性
  • 即使在双方 “同时” 执行关注操作,最终数据库里的结果,也是 like 表里面有一条关于 A 和 B 的记录,而且 relation_ship 的值是 3, 并且 friend 表里面也有了 A 和 B 的这条记录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/526150.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据链路层协议 ——— 以太网协议

文章目录 链路层解决的问题以太网协议认识以太网以太网帧格式认识MAC地址对比理解MAC地址和IP地址认识MTUMUT对IP协议的影响MTU对UDP协议的影响MTU对TCP协议的影响数据跨网络传输的过程 ARP协议ARP协议的作用ARP数据的格式ARP协议的工作流程 链路层解决的问题 IP拥有将数据跨网…

【前端知识】Cookie, Session,Token和JWT的发展及区别(二)

【前端知识】Cookie, Session,Token和JWT的发展及区别&#xff08;二&#xff09; 4. Session4.1 Session的背景及定义4.2 Session的特点&#x1f44d;4.2.1 Session的特点&#x1f440;4.2.2 Session保存的位置 4.3 Session的一些重要/常用属性4.4 Session的认证流程4.5 Sessi…

Python数据清洗:Python和Pandas数据清洗的实用教程

前言&#xff1a; 技术书籍是学习技术知识的重要资源之一。读技术书可以帮助我们学习新技能和知识&#xff0c;技术书籍提供了可靠的、全面的信息&#xff0c;帮助我们快速学习新技能和知识。同时技术书籍有助于保持你的竞争力&#xff0c;因为它们提供了最新的技术知识和实践。…

什么? 你还没用过 Cursor? 智能 AI 代码生成工具 Cursor 安装和使用介绍

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;蚂蚁集团高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《EffectiveJava》独家解析》专栏作者。 热门文章推荐…

ChatGPT 免费体验来了

露个相吧 1、相信很多小伙伴们面试或者工作中会遇到数组扁平化这一问题&#xff0c;如今正是 chatgpt 大火的时候&#xff0c;何不让我们试试水呢&#xff0c;所以让我们的 chatgpt 用js帮我们写一个数组扁平化吧 2、这就&#xff1f;这就&#xff1f;这就写出来了&#xff1f…

【JavaScript数据结构与算法】字符串类(反转字符串中的单词)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端&#xff08;Node.js&#xff09; &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;…

【大数据基础】淘宝双11数据分析与预测

https://dblab.xmu.edu.cn/post/8116/ 问题 问题1 mysql登录需要密码 https://cloud.tencent.com/developer/beta/article/1142525 这个很神奇&#xff0c;我密码输1就进去了 为避免出问题&#xff0c;把解决方案放这里&#xff1a; https://blog.csdn.net/qq_34771403/ar…

【路径规划】全局路径规划算法——蚁群算法(含python实现)

文章目录 参考资料1. 简介2. 基本思想3. 算法精讲4. 算法步骤5. python实现 参考资料 路径规划与轨迹跟踪系列算法蚁群算法原理及其实现蚁群算法详解&#xff08;含例程&#xff09;图说蚁群算法(ACO)附源码蚁群算法Python实现 1. 简介 蚁群算法&#xff08;Ant Colony Algo…

mybatis-plus 自动填充的时间跟真实时间相差8小时

项目中 用到了以下两个字段,分别是插入数据时间和更新数据时间&#xff0c;用的mybatis-plus自动填充,结果发现填充的时间跟真实时间相差很多。查了一些资料&#xff0c;找到了解决方案&#xff1a; 1. 下图是我的mysql没有进行配置之前的时区配置,这里的CST包括了4个时区,分别…

一百零六、Hive312的计算引擎由MapReduce(默认)改为Spark(亲测有效)

一、Hive引擎包括&#xff1a;默认MR、tez、spark 在低版本的hive中&#xff0c;只有两种计算引擎mr, tez 在高版本的hive中&#xff0c;有三种计算引擎mr, spark, tez 二、Hive on Spark和Spark on Hive的区别 Hive on Spark&#xff1a;Hive既存储元数据又负责SQL的解析&…

【0基础】学习solidity开发智能合约-初识solidity

本篇课程开始&#xff0c;我们来学习一下如何使用solidity开发智能合约&#xff0c;由于博主对于solidity的学习&#xff0c;也是自学的&#xff0c;所以一些不足或有纰漏之处还望指出&#xff0c;大家共同进步&#xff0c;本系列课程会分很多节课讲述&#xff0c;从入门到进阶…

安装navicat详细流程

1.双击已下载好的navicat安装包&#xff0c;点击"下一步" 2.点击我同意&#xff0c;在点击"下一步" 3.设置navicat安装路劲&#xff0c; 至少要保证磁盘有90M的空间。在这里选择默认的安装路径&#xff0c;也可以根据自身情况安装到其他盘。 4.默认&#x…

一个几乎全民都会的算法——二分查找

为什么说二分查找是全民都会的算法&#xff1f; 20年前央视2套有一档叫《幸运52》的综艺节目&#xff0c;其中一个环节叫《幸运超市》&#xff0c;每一期已故著名主持人咏哥都会给佳宾们出示几个商品&#xff0c;凡是佳宾猜中价格的&#xff0c;就能获赠这件商品。这档节目红极…

C++ 类和对象(中)构造函数 和 析构函数 ,const成员

上篇链接&#xff1a;C 类和对象&#xff08;上&#xff09;_chihiro1122的博客-CSDN博客 类的6个默认成员函数 我们在C当中&#xff0c;在写一些函数的时候&#xff0c;比如在栈的例子&#xff1a; 如上述例子&#xff0c;用C 返回这个栈是否为空&#xff0c;直接返回的话&am…

Selenium+Pytest自动化测试框架实战

前言 1、Selenium是一个免费的(开源)自动化测试组件&#xff0c;适用于跨不同浏览器和平台的Web应用程序【selenium是一个自动化工具&#xff0c;而不是自动化框架】。它非常类似于HP Quick Test Pro (QTP现在叫UFT)&#xff0c;只是Selenium侧重于自动化基于Web的应用程序。使…

初、高中生到底该不该学习编程?

从小学&#xff0c;到初中&#xff0c;再到高中&#xff0c;知识的提升主要体现在一个方面上&#xff0c;就是知识越来越抽象了。很多孩子在初中成绩还可以&#xff0c;到了高中就跟不上了&#xff0c;这是最主要的一个原因。 编程主要就是要求学习它的人&#xff0c;有较强的…

2023武生院计科专升本指南

自我介绍一下&#xff0c;我叫啊超&#xff0c;22级专升本上岸武生院考了211的计应学长&#xff0c;社恐&#xff0c;不善言辞&#xff0c;出门都走下水道&#xff0c;吃饭因社恐&#xff0c;屡次不敢买单。单身可撩&#xff0c;哈哈哈~ 我只是提出自己的一些个人建议&#xff…

utittest和pytest中mock的使用详细介绍

Mock是Python中一个用于支持单元测试的库&#xff0c;它的主要功能是使用mock对象替代掉指定的Python对象&#xff0c;以达到模拟对象的行为。 python3.3 以前&#xff0c;mock是第三方库&#xff0c;需要安装之后才能使用。python3.3之后&#xff0c;mock作为标准库内置到 un…

防火墙(firewall)

前言 计算机的安全性历来就是人们热衷的话题之一。而随着Internet的广泛应用&#xff0c;人们在扩展了获取和发布能力的同时也带来信息被污染和破坏的危险。这些安全问题主要是由网络的开放性、无边界性、自由性造成的&#xff0c;还包括以下一些因素。 1. 计算机操作系统本身…

分布式补充技术 01.AOP技术

01.AOP技术是对于面向对象编程&#xff08;OOP&#xff09;的补充。是按照OCP原则进行的编写&#xff0c;(ocp是修改模块权限不行&#xff0c;扩充可以) 02.写一个例子&#xff1a; 创建一个新的java项目&#xff0c;在main主启动类中&#xff0c;写如下代码。 package com.co…