簡體   English   中英

獲取 mysql(innodb) AUTO_INCREMENT Column、JDBC/getGeneratedKeys()/last_insert_id (in OkPacket) 和 LAST_INSERT_ID() 的方法

[英]Ways to get mysql(innodb) AUTO_INCREMENT Column, JDBC/getGeneratedKeys()/last_insert_id (in OkPacket) and LAST_INSERT_ID()

According to mysql doc: https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-usagenotes-last-insert-id.html

有時,使用 SELECT LAST_INSERT_ID() 查詢可能會很棘手,因為該函數的值僅限於連接。 因此,如果在同一連接上發生其他一些查詢,則該值將被覆蓋。 另一方面,getGeneratedKeys() 方法由 Statement 實例限定,因此即使其他查詢發生在同一個連接上,但不能在同一個 Statement 實例上,也可以使用它。

首先,我考慮LAST_INSERT_ID() SQL function LAST_INSERT_ID()是連接安全的,但不是會話/事務/語句安全的。 它不能在生產中使用,因為在實際環境中,一個連接中的多個會話/事務/語句非常常見。

然后getGeneratedKeys()使用 JDBC。 當我在 Java 中使用getGeneratedKeys()時。 我想看看它在數據庫中的作用。 在使用 JDBC 簡單地插入演示表並使用自動增加主鍵后,我嘗試使用以下語句跟蹤 SQL 語句:

SET GLOBAL log_output = 'TABLE'; 
SET GLOBAL general_log = 'ON';
SELECT * FROM mysql.general_log;

我確定新行已正確插入,並且getGeneratedKeys()將自動遞增的 id 帶回來。 但是,我只發現 JDBC 之前執行的插入語句,以及一些 static 數據,如"SELECT database(),version()..." 現在,結論是, getGeneratedKeys()不執行任何 SQL 語句來獲取自動遞增的 id。 然后我找到了另一種可能性,我調試到調用堆棧,請參閱 JDBC get auto-incremented id from object 稱為OkPacket 它有一個名為last_insert_id的屬性。 終於在這里找到了。

我的問題是:

  1. 真的沒有辦法使用純 SQL 語句(不帶 JDBC)獲得 STATEMENT SAFE(至少事務安全)自動遞增 id 嗎?
  2. OkPacket如何在引擎蓋下工作? 它如何獲得聲明安全自動增加ID? 也許它在 MySQL 驅動程序或 Z62A004B95946BB97AZ541AFA471

MySQL 有一個 API,客戶端使用它來傳達命令並獲取結果。

實際上,它有兩個 forms 這個 API。 一種稱為“SQL 協議”,其中語句作為字符串發送,例如 SELECT * FROM mytable 等。另一種形式稱為“二進制協議”,其中命令使用服務器識別的某些字節發送,即使它們不是人類可讀的字符串。

某些命令可以通過 SQL 協議或二進制協議執行。 例如, START TRANSACTIONCOMMITPREPARE ...這些命令有文本 SQL 語句,但也有 API 調用這些命令的非文本方式。

你當然可以查詢SELECT LAST_INSERT_ID(); 並獲取最近生成的 id,但只有最近的。 當您閱讀時,另一個 INSERT 語句將覆蓋此值。

OkPacket由二進制協議填充。 也就是說,MySQL 服務器返回一個 OkPacket,其中包含有關任何語句執行的幾條元數據。

https://github.com/mysql/mysql-connector-j/blob/release/8.0/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/OkPacket.java#L55

Ok 數據包包括以下內容:

  • 受影響的行數(如果有)
  • 最后插入 ID(如果有)
  • 狀態標志
  • 警告計數(如果有)
  • 帶有錯誤消息的字符串(如果有)

記錄 OK 數據包的 MySQL 服務器代碼非常詳盡,並附有示例:

https://github.com/mysql/mysql-server/blob/8.0/sql/protocol_classic.cc#L665-L838

無法獲取早期 SQL 語句的 OK 數據包。 客戶端必須在語句執行后立即保存結果。 在 JDBC 驅動程序等面向對象的代碼中,將其存儲在 NativeResultset object 中是有意義的: https://github.com/protocolrelease impl/java/com/mysql/cj/protocol/a/result/NativeResultset.java#L77-L82

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM