繁体   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