zoukankan      html  css  js  c++  java
  • MySQL中的 ”SELECT FOR UPDATE“ 一次实践

    背景

    最近工作中遇到一个问题,两个不同的线程会对数据库里的一条数据做修改,如果不加锁的话,会得到错误的结果。

    就用了MySQL中for update 这种方式来实现

    本文主要测试主键、唯一索引和普通索引使用for update 会锁哪些数据

    使用两个console来模拟两个事务运行的情况

    表结构

    /*
     Navicat Premium Data Transfer
    
     Source Server         : localhost
     Source Server Type    : MySQL
     Source Server Version : 50730
     Source Host           : localhost:3306
     Source Schema         : test
    
     Target Server Type    : MySQL
     Target Server Version : 50730
     File Encoding         : 65001
    
     Date: 18/12/2020 20:28:58
    */
    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for select_for_update_test
    -- ----------------------------
    DROP TABLE IF EXISTS `select_for_update_test`;
    CREATE TABLE `select_for_update_test` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(20) NOT NULL,
      `age` int(11) NOT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `name` (`name`),
      KEY `age` (`age`)
    ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of select_for_update_test
    -- ----------------------------
    BEGIN;
    INSERT INTO `select_for_update_test` VALUES (1, 'a', 1);
    INSERT INTO `select_for_update_test` VALUES (2, 'b', 2);
    INSERT INTO `select_for_update_test` VALUES (3, 'c', 3);
    INSERT INTO `select_for_update_test` VALUES (4, 'd', 4);
    INSERT INTO `select_for_update_test` VALUES (5, 'e', 5);
    INSERT INTO `select_for_update_test` VALUES (6, 'f', 6);
    INSERT INTO `select_for_update_test` VALUES (7, 'g', 7);
    INSERT INTO `select_for_update_test` VALUES (8, 'h', 8);
    COMMIT;
    
    SET FOREIGN_KEY_CHECKS = 1;
    

    主键的影响

    • 选一行数据
    console1
    
    START TRANSACTION;
    SELECT * FROM select_for_update_test WHERE id = 1 FOR UPDATE;
    
    console2
    SELECT * FROM select_for_update_test WHERE id = 1 FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE id = 2 FOR UPDATE; 不会锁
    
    • 选取多行记录
    console1
    
    START TRANSACTION;
    SELECT * FROM select_for_update_test WHERE id >= 2 AND id <= 5 FOR UPDATE;
    
    console2
    
    SELECT * FROM select_for_update_test WHERE id = 1 FOR UPDATE; 不会锁
    
    SELECT * FROM select_for_update_test WHERE id = 3 FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE id = 6 FOR UPDATE; 会锁
    

    唯一索引的影响

    • 选一行数据
    console1
    
    START TRANSACTION;
    SELECT * FROM select_for_update_test WHERE `name` = 'a' FOR UPDATE;
    
    console2
    
    SELECT * FROM select_for_update_test WHERE `name` = 'a' FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE `name` = 'b' FOR UPDATE; 不会锁
    
    • 选取多行记录1
    console1
    
    START TRANSACTION;
    SELECT * FROM select_for_update_test WHERE `name` >= 'b' AND `name` <= 'e' FOR UPDATE;
    
    console2
    
    SELECT * FROM select_for_update_test WHERE `name` = 'a' FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE `name` = 'c' FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE `name` = 'f' FOR UPDATE; 会锁
    
    • 选取多行记录2
    console1
    
    START TRANSACTION;
    SELECT * FROM select_for_update_test WHERE `name` >= 'c' AND `name` <= 'e' FOR UPDATE;
    
    console2
    
    SELECT * FROM select_for_update_test WHERE `name` = 'b' FOR UPDATE; 不会锁
    
    SELECT * FROM select_for_update_test WHERE `name` = 'c' FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE `name` = 'f' FOR UPDATE; 会锁
    

    普通索引的影响

    • 选一行数据
    console1
    
    START TRANSACTION;
    SELECT * FROM select_for_update_test WHERE age = 1 FOR UPDATE;
    
    console2
    
    SELECT * FROM select_for_update_test WHERE age = 1 FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE age = 2 FOR UPDATE; 不会锁
    
    • 选取多行记录1
    console1
    
    START TRANSACTION;
    SELECT * FROM select_for_update_test WHERE age >= 2 AND age <= 5 FOR UPDATE;
    
    console2
    
    
    SELECT * FROM select_for_update_test WHERE age = 1 FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE age = 3 FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE age = 6 FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE age = 8 FOR UPDATE; 不会锁
    
    • 选取多行记录2
    console1
    
    START TRANSACTION;
    SELECT * FROM select_for_update_test WHERE age >= 3 AND age <= 5 FOR UPDATE;
    
    console2
    
    
    SELECT * FROM select_for_update_test WHERE age = 2 FOR UPDATE; 不会锁
    
    SELECT * FROM select_for_update_test WHERE age = 3 FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE age = 6 FOR UPDATE; 会锁
    
    SELECT * FROM select_for_update_test WHERE age = 8 FOR UPDATE; 不会锁
    
  • 相关阅读:
    判断鼠标在按钮区域上面
    在MFC下绘制直线,使用橡皮筋技术,可以使直线效果跟随鼠标移
    三缓冲
    MFC--自己优化滚动条的双缓冲绘图方法
    MFC视图切换大全总结
    各种线程:事件、互斥量、信号量、临界区 的用法,我自己做的,有用,附件里面有,博客附件里面有
    http://www.cctry.com/forum.php?mod=viewthread&tid=800&reltid=4131&pre_thread_id=0&pre_pos=3&ext=
    关于Mac下pycharm无法调用摄像头权限的问题
    终于理解清楚attention,利用attention对黄金价格进行预测
    tensorboard在colab中的实现
  • 原文地址:https://www.cnblogs.com/eaglelihh/p/14156817.html
Copyright © 2011-2022 走看看