主頁 > 後端開發 > 面試官:MySQL 自增主鍵一定是連續的嗎?大部分人都會答錯!

面試官:MySQL 自增主鍵一定是連續的嗎?大部分人都會答錯!

2023-05-30 07:43:14 後端開發

測驗環境:

MySQL版本:8.0

資料庫表:T (主鍵id,唯一索引c,普通欄位d)

如果你的業務設計依賴于自增主鍵的連續性,這個設計假設自增主鍵是連續的,但實際上,這樣的假設是錯的,因為自增主鍵不能保證連續遞增,

推薦一個開源免費的 Spring Boot 實戰專案:

https://github.com/javastacks/spring-boot-best-practice

一、自增值的屬性特征:

1. 自增主鍵值是存盤在哪的?

MySQL5.7版本

在 MySQL 5.7 及之前的版本,自增值保存在記憶體里,并沒有持久化,每次重啟后,第一次打開表的時候,都會去找自增值的最大值 max(id),然后將 max(id)+1 作為這個表當前的自增值,

MySQL8.0之后版本

在 MySQL 8.0 版本,將自增值的變更記錄在了 redo log 中,重啟的時候依靠 redo log 恢復重啟之前的值,

可以通過看表詳情查看當前自增值,以及查看表引數詳情AUTO_INCREMENT值(AUTO_INCREMENT就是當前資料表的自增值)

2. 自增主鍵值的修改機制?

在表t中,我定義了主鍵id為自增值,在插入一行資料的時候,自增值的行為如下:

  1. 如果插入資料時 id 欄位指定為 0、null 或未指定值,那么就把這個表當前的 AUTO_INCREMENT 值填到自增欄位;
  2. 如果插入資料時 id 欄位指定了具體的值,就直接使用陳述句里指定的值,

根據要插入的值和當前自增值的大小關系,自增值的變更結果也會有所不同,假設,某次要插入的值是 X,當前的自增值是 Y,

  1. 如果 X<Y,那么這個表的自增值不變;
  2. 如果 X≥Y,就需要把當前自增值修改為新的自增值,

二、新增陳述句自增主鍵是如何變化的:

我們執行以下SQL陳述句,來觀察自增主鍵是如何進行變化的

insert into t values(null, 1, 1);

流程圖如下所示

流程步驟:

  • AUTO_INCREMENT=1 (表示下一次插入資料時,如果需要自動生成自增值,會生成 id=1,)
  • insert into t values(null, 1, 1) (執行器呼叫 InnoDB 引擎介面寫入一行,傳入的這一行的值是 (0,1,1))
  • get AUTO_INCREMENT=1 (InnoDB 發現用戶沒有指定自增 id 的值,獲取表 t 當前的自增值 1 )
  • AUTO_INCREMENT=2 insert into t values(1, 1, 1) (將傳入的行的值改成 (1,1,1),并把自增值改為2)
  • insert (1,1,1) 執行插入操作,至此流程結束

大家可以發現,在這個流程當中是先進行自增值的+1,在進行新增陳述句的執行的,大家可以發現這個操作并沒有進行原子操作,如果SQL陳述句執行失敗,那么自增是不是就不會連續了呢?

三、自增主鍵值不連續情況:(唯一主鍵沖突)

當我執行以下SQL陳述句時

insert into t values(null, 1, 1);

第一次我們可以進行新增成功,根據自增值的修改機制,如果插入資料時 id 欄位指定為 0、null 或未指定值,那么就把這個表當前的 AUTO_INCREMENT 值填到自增欄位;

當我們第二次在執行以下SQL陳述句時,就會出現錯誤,因為我們表中c欄位是唯一索引,會出現Duplicate key error錯誤導致新增失敗,

例如:

  • AUTO_INCREMENT=2 (表示下一次插入資料時,如果需要自動生成自增值,會生成 id=2,)
  • insert into t values(null, 1, 1) (執行器呼叫 InnoDB 引擎介面寫入一行,傳入的這一行的值是 (0,1,1))
  • get AUTO_INCREMENT=2 (InnoDB 發現用戶沒有指定自增 id 的值,獲取表 t 當前的自增值 2 )
  • AUTO_INCREMENT=3 insert into t values(2, 1, 1) (將傳入的行的值改成 (2,1,1),并把自增值改為3)
  • insert (2,1,1) 執行插入操作,由于已經存在 c=1 的記錄,所以報 Duplicate key error,陳述句回傳,

可以看到,這個表的自增值改成 3,是在真正執行插入資料的操作之前,這個陳述句真正執行的時候,因為碰到唯一鍵 c 沖突,所以 id=2 這一行并沒有插入成功,但也沒有將自增值再改回去,所以,在這之后,再插入新的資料行時,拿到的自增 id 就是 3,也就是說,出現了自增主鍵不連續的情況,

四、自增主鍵值不連續情況:(事務回滾)

其實事務回滾原理也和上面一樣,都是因為例外導致新增失敗,但是自增值沒有進行回退,

五、自增主鍵值不連續情況:(批量插入)

批量插入資料的陳述句,MySQL 有一個批量申請自增 id 的策略:

  1. 陳述句執行程序中,第一次申請自增 id,會分配 1 個;
  2. 1 個用完以后,這個陳述句第二次申請自增 id,會分配 2 個;
  3. 2 個用完以后,還是這個陳述句, 第三次申請自增 id,會分配 4 個;
  4. 依此類推,同一個陳述句去申請自增 id,每次申請到的自增 id 個數都是上一次的兩倍,

執行以下SQL陳述句(在表t中先新增了4條資料,在創建表tt把表t資料進行批量新增)

insert into t values(null, 1,1);
insert into t values(null, 2,2);
insert into t values(null, 3,3);
insert into t values(null, 4,4);
create table tt like t;
insert into tt(c,d) select c,d from t;

insert into tt values(null, 5,5);

第一次申請到了 id=1,第二次被分配了 id=2 和 id=3, 第三次被分配到 id=4 到 id=7,當我們再執行 insert into t2 values(null, 5,5),實際上插入的資料就是(8,5,5),出現了自增主鍵不連續的情況,

六、自增主鍵值的優化

1.什么是自增鎖

自增鎖是一種比擬非凡的表級鎖,并且在事務向蘊含了 AUTO_INCREMENT 列的表中新增資料時就會去持有自增鎖,假如事務 A 正在做這個操作,如果另一個事務 B 嘗試執行 INSERT陳述句,事務 B 會被阻塞住,直到事務 A 開釋自增鎖,

2.自增鎖有哪些優化

在 MySQL 5.0 版本的時候,自增鎖的范圍是陳述句級別,也就是說,如果一個陳述句申請了一個表自增鎖,這個鎖會等陳述句執行結束以后才釋放,顯然,這樣設計會影響并發度,在MySQL 5.1.22 版本引入了一個新策略,新增引數 innodb_autoinc_lock_mode,默認值是 1,

傳統模式(Traditional)

這個引數的值被設定為 0 時,表示采用之前 MySQL 5.0 版本的策略,即陳述句執行結束后才釋放鎖;

傳統模式他可以保證資料一致性,但是如果有多個事務并發的執行 INSERT 操作,AUTO-INC的存在會使得 MySQL 的性能略有降落,因為同時只能執行一條 INSERT 陳述句,

間斷模式(Consecutive)

這個引數的值被設定為 1 時:普通 insert 陳述句,自增鎖在申請之后就馬上釋放;類似 insert … select 這樣的批量插入資料的陳述句,自增鎖還是要等陳述句結束后才被釋放;

間斷模式他可以保證資料一致性,但是如果有多個事務并發的執行 INSERT 批量操作時,就會進行鎖等待狀態,如果我們業務插入資料量很大時,這個時候MySQL的性能就會大大下降,

穿插模式(Interleaved)

這個引數的值被設定為 2 時,所有的申請自增主鍵的動作都是申請后就釋放鎖,

穿插模式他沒有進行任何的上鎖設定,在一定情況下是保證了MySQL的性能,但是他無法保證資料的一致性,如果我們在穿插模式下進行主從復制時,如果你的binlog格式不是row格式,主從復制就會出現不一致,

七、MySQL8.0做了哪些優化

在MySQL8.0之后版本,已經默認設定為 innodb_autoinc_lock_mode=2binlog_format=row.,這樣更有利與我們在 insert … select 這種批量插入資料的場景時,既能提升并發性,又不會出現資料一致性問題,

著作權宣告:本文為CSDN博主「又 欠」的原創文章,遵循CC 4.0 BY-SA著作權協議,轉載請附上原文出處鏈接及本宣告,原文鏈接:https://blog.csdn.net/qq_48157004/article/details/128356734

近期熱文推薦:

1.1,000+ 道 Java面試題及答案整理(2022最新版)

2.勁爆!Java 協程要來了,,,

3.Spring Boot 2.x 教程,太全了!

4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!

5.《Java開發手冊(嵩山版)》最新發布,速速下載!

覺得不錯,別忘了隨手點贊+轉發哦!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/553738.html

標籤:其他

上一篇:VST實體(5)節點(NODE) 二、節點的遍歷

下一篇:返回列表

標籤雲
其他(159930) Python(38185) JavaScript(25462) Java(18151) C(15233) 區塊鏈(8268) C#(7972) AI(7469) 爪哇(7425) MySQL(7215) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5873) 数组(5741) R(5409) Linux(5344) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4578) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2434) ASP.NET(2403) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1977) 功能(1967) Web開發(1951) HtmlCss(1949) C++(1926) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1878) .NETCore(1862) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • 面試官:MySQL 自增主鍵一定是連續的嗎?大部分人都會答錯!

    ## 測驗環境: > MySQL版本:8.0 資料庫表:T (主鍵id,唯一索引c,普通欄位d) ![](http://img.javastack.cn/1685072039483867.png) 如果你的業務設計依賴于自增主鍵的連續性,這個設計假設自增主鍵是連續的。但實際上,這樣的假設是錯的,因為 ......

    uj5u.com 2023-05-30 07:43:14 more
  • VST實體(5)節點(NODE) 二、節點的遍歷

    二、節點的遍歷 每一個節點都有一個index值,用于描述其在相同level,相同父節點下的序號,但是,遍歷時并不能利用這個值,因為這個值是變化的,當進行排序,插入節點、洗掉節點等等操作時,這個index會發生改變。 同樣的,vst.AbsoluteIndex(node)回傳的是某一節點在VST中的絕 ......

    uj5u.com 2023-05-30 07:43:05 more
  • c語言,函式的址傳遞例子

    編碼如下:#include <stdio.h> void swap(int* x,int* y ){ int tmp; tmp=*x; *x=*y; *y=tmp ; }; int main(){ int a=4; int b=5; printf("befer\n"); printf("a=%d\n ......

    uj5u.com 2023-05-30 07:43:01 more
  • Python日期帶時區轉換工具類總結

    @[TOC] # 1.背景 最近專案是國際專案,所以需要經常需要用到UTC時間和local時間的轉換。 所以整理了一下時間戳工具類,方便使用。 這里主要用到的包就是datatime、time、pytz。 # 2. 遇到的坑 直接看測驗案例 ```python tzinfo=pytz.timezone ......

    uj5u.com 2023-05-30 07:42:57 more
  • 詳談Java中Properties配置類怎么用

    本文將為大家詳細講解Java中Properties配置類怎么用,這是我們進行開發時經常用到的知識點,也是大家在學習Java中很重要的一個知識點,更是我們在面試時有可能會問到的問題!文章較長,干貨滿滿,建議大家收藏慢慢學習。文末有本文重點總結,主頁有全系列文章分享。技術類問題,歡迎大家和我們一起交流討... ......

    uj5u.com 2023-05-30 07:42:53 more
  • Python工具箱系列(三十四)

    SQLAlchemy是著名的ORM(Object Relational Mapping-物件關系映射)框架。其主要作用是在編程中,把面向物件的概念跟資料庫中表的概念對應起來。對許多語言(例如JAVA/PYTHON)來說就是定義一個物件,并且這個物件對應著一張資料庫的表。而這個物件的實體,就對應著表中... ......

    uj5u.com 2023-05-30 07:42:45 more
  • Python壓縮JS檔案,重點是 slimit

    摘要:Python Web程式員必看系列,學習如何壓縮 JS 代碼。 本文分享自華為云社區《Python壓縮JS檔案,PythonWeb程式員必看系列,重點是 slimit》,作者: 夢想橡皮擦 。 本篇博客將學習壓縮 JS 代碼,首先要學習的模塊是 jsmin。 jsmin 庫 Python 中的 ......

    uj5u.com 2023-05-30 07:42:36 more
  • 【重學C++】05 | 說透右值參考、移動語意、完美轉發(下)

    ## 文章首發 [【重學C++】05 | 說透右值參考、移動語意、完美轉發(下)](https://mp.weixin.qq.com/s/w7yXp6efE7_V0EHxXWJiJA) ## 引言 大家好,我是只講技術干貨的會玩code,今天是【重學C++】的第五講,在第四講《[【重學C++】04 ......

    uj5u.com 2023-05-30 07:42:31 more
  • JavaWeb編程面試題——MyBatis

    面試題==知識點,這里所記錄的面試題并不針對于面試者,而是將這些面試題作為技能知識點來看待。不以刷題進大廠為目的,而是以學習為目的。這里的知識點會持續更新,目錄也會隨時進行調整。 ......

    uj5u.com 2023-05-30 07:42:26 more
  • Python連接es筆記二之查詢方式匯總

    > 本文首發于公眾號:Hunter后端 > 原文鏈接:[Python連接es筆記二之查詢方式匯總](https://mp.weixin.qq.com/s/0Yn5c-U9pBWrSC5HrCgWog) 上一節除了介紹使用 Python 連接 es,還有最簡單的 query() 方法,這一節介紹一下幾 ......

    uj5u.com 2023-05-30 07:41:47 more