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

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

2023-06-26 07:35:25 後端開發

測驗環境:

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/555893.html

標籤:Java

上一篇:【爬蟲案例】用Python爬大麥網任意城市的近期演出活動!

下一篇:返回列表

標籤雲
其他(161553) Python(38244) JavaScript(25513) Java(18252) C(15238) 區塊鏈(8272) C#(7972) AI(7469) 爪哇(7425) MySQL(7266) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4606) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2437) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1971) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(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) ![](https://img2023.cnblogs.com/other/1218593/202306/1218593-20230625093159551-1903519851.png) 如果你的業務 ......

    uj5u.com 2023-06-26 07:35:25 more
  • 【爬蟲案例】用Python爬大麥網任意城市的近期演出活動!

    [toc] # 一、爬取目標 大家好,我是[@馬哥python說](https://www.zhihu.com/people/13273183132) ,一枚10年程式猿。 今天分享一期python爬蟲案例,爬取目標是大麥網近期演出活動:[- 大麥搜索](https://search.damai.c ......

    uj5u.com 2023-06-25 07:39:19 more
  • [ARM 匯編]高級部分—性能優化與除錯—3.4.2 ARM匯編程式除錯技

    在ARM匯編程式開發程序中,除錯是一個關鍵環節。適當的除錯技巧可以幫助我們更快地定位問題、解決問題,從而提高開發效率。本節將講解一些ARM匯編程式的除錯技巧,并通過實體進行講解。 1. **使用GDB除錯** GDB(GNU除錯器)是一個功能強大的除錯工具,它支持ARM匯編程式的除錯。以下是使用GD ......

    uj5u.com 2023-06-25 07:39:09 more
  • 一文了解Go語言的匿名函式

    # 1. 引言 無論是在`Go`語言還是其他編程語言中,匿名函式都扮演著重要的角色。在本文中,我們將詳細介紹`Go`語言中匿名函式的概念和使用方法,同時也提供一些考慮因素,從而幫助在匿名函式和命名函式間做出選擇。 # 2. 基本定義 匿名函式是一種沒有函式名的函式。它是在代碼中直接定義的函式,沒有被 ......

    uj5u.com 2023-06-25 07:39:04 more
  • Scala練習題

    # SQL join語法案例 Data: ```Plain Text order.txt order011,u001,300 order012,u002,200 order023,u006,100 order056,u007,300 order066,u003,500 order055,u004,3 ......

    uj5u.com 2023-06-25 07:38:59 more
  • C++面試八股文:std::vector和std::list,如何選擇?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第24面: > 面試官:`list`用過嗎? > > 二師兄:嗯,用過。 > > 面試官:請講一下`list`的實作原理。 > > 二師兄:`std::list`被稱為雙向鏈表,和C中手寫雙向鏈表本質上沒有大的區別。`list`物件中有兩個指標,一個 ......

    uj5u.com 2023-06-25 07:38:54 more
  • Python潮流周刊#8:Python 3.13 計劃將解釋器提速 50%!

    你好,我是貓哥。這里每周分享優質的 Python 及通用技術內容,部分為英文,已在小標題注明。(標題取自其中一則分享,不代表全部內容都是該主題,特此宣告。) 首發于我的博客:[https://pythoncat.top/posts/2023-06-24-weekly](https://pythonc ......

    uj5u.com 2023-06-25 07:38:32 more
  • 55基于java的在線零食超市系統設計與實作

    基于java在線零食超市系統設計與實作,可適用于零食小吃,在線零食小吃超市,線上超市,線上零食商城,美食商城,美食超市,校園超市,零食資訊等等。 ......

    uj5u.com 2023-06-25 07:37:44 more
  • Cookie和Session

    # Cookie和Session ## 會話 - 什么是會話? 會話是瀏覽器和服務器之間的多次請求和回應 也就是說,從瀏覽器訪問服務器開始,到訪問服務器結束,瀏覽器關閉為止的這段時間內容產生的多次請求和回應,合起來叫做瀏覽器和服務器之間的一次會話 - 有狀態會話:一個網站知曉你登陸過、存盤了一些基本 ......

    uj5u.com 2023-06-25 07:32:02 more
  • 【技識訓累】C語言中的指標【一】

    博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ......

    uj5u.com 2023-06-24 07:33:33 more