[英]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
的属性。 终于在这里找到了。
我的问题是:
OkPacket
如何在引擎盖下工作? 它如何获得声明安全自动增加ID? 也许它在 MySQL 驱动程序或 Z62A004B95946BB97AZ541AFA471MySQL 有一个 API,客户端使用它来传达命令并获取结果。
实际上,它有两个 forms 这个 API。 一种称为“SQL 协议”,其中语句作为字符串发送,例如 SELECT * FROM mytable 等。另一种形式称为“二进制协议”,其中命令使用服务器识别的某些字节发送,即使它们不是人类可读的字符串。
某些命令可以通过 SQL 协议或二进制协议执行。 例如, START TRANSACTION
、 COMMIT
、 PREPARE
...这些命令有文本 SQL 语句,但也有 API 调用这些命令的非文本方式。
你当然可以查询SELECT LAST_INSERT_ID();
并获取最近生成的 id,但只有最近的。 当您阅读时,另一个 INSERT 语句将覆盖此值。
OkPacket
由二进制协议填充。 也就是说,MySQL 服务器返回一个 OkPacket,其中包含有关任何语句执行的几条元数据。
Ok 数据包包括以下内容:
记录 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.