Xeo*_*eos 7 mysql triggers innodb auto-increment last-insert-id
我有一个BEFORE INSERT TRIGGER用于计算AUTO_INCREMENT列(id_2)的值.
id_1 | id_2 | data
1 | 1 | 'a'
1 | 2 | 'b'
1 | 3 | 'c'
2 | 1 | 'a'
2 | 2 | 'b'
2 | 3 | 'c'
2 | 4 | 'a'
3 | 1 | 'b'
3 | 2 | 'c'
Run Code Online (Sandbox Code Playgroud)
我有PRIMARY(id_1,id_2),我正在使用InnoDB.以前,该表使用的是MyISAM,我没有遇到任何问题:id_2设置为AUTO_INCREMENT,所以每个新条目id_1都会id_2自行生成新的.现在,在切换到InnoDB后,我有这个触发器做同样的事情:
SET @id = NULL;
SELECT COALESCE(MAX(id_2) + 1, 1) INTO @id FROM tbl WHERE id_1 = NEW.id_1;
SET NEW.id_2= @id;
Run Code Online (Sandbox Code Playgroud)
它完美地工作,除了现在LAST_INSERT_ID()有错误的值(它返回0).很多代码都取决于LAST_INSERT_ID()正确性.但是,自MySQL 5.0.12以来,对TRIGGERS LAST_INSERT_ID内所做的任何更改都不会影响全局值.有没有办法绕过这个?我可以通过调用轻松设置AFTER UPDATE TRIGGER更改,但任何客户端都将设置为0.LAST_INSERT_IDLAST_INSERT_ID(NEW.id_2)LAST_INSERT_ID
是否有任何工作解决方法迫使MySQL维持LAST_INSERT_ID触发器内部状态的变化?有没有其他选择,除了切换回支持开箱即用的MyISAM或SELECT max(id_2) FROM tbl WHERE id_1 = :id作为事务的一部分运行另一个以确保找到的行将是之前插入的行?
> SHOW CREATE TABLE tbl;
CREATE TABLE `tbl` (
`id_1` int(11) NOT NULL,
`id_2` int(11) NOT NULL,
`data` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id_1`,`id_2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Run Code Online (Sandbox Code Playgroud)
例:
INSERT INTO tbl (id_1, id_2, data) VALUES (1, NULL, 'd');
SELECT LAST_INSERT_ID();
Run Code Online (Sandbox Code Playgroud)
第一个语句将行1 | 4 | 'd'插入表中.第二个声明将返回0,但我需要它返回4.
正如Ravinder Reddy所说,添加关于系统的简短说明:
我有一个包含篮子的表,我有另一个tbl包含项目的表().该篮由应用程序创建的,并从分配一个ID AUTO_INCREMENT上筐表.任务是在id = ,into的篮子中插入项目,在该篮子的范围内id_1为tbl它们分配一个唯一的ID.每个项目都有一些data与之关联,可能会在同一个篮子中重复.因此,在实践中,我想所有的存储data条目的单个内篮,然后可以参考(和检索)通过这些个别条目id_1- id_2对.
根据您的表结构描述,很明显它没有可以自动生成值的主键字段。MySQLinformation_schema.tables不保存任何auto_increment值,除非null那些未定义的字段auto_increment。
触发问题:
触发器主体中使用的代码块似乎取决于 id 字段的显式计算和输入。它没有使用auto_increment字段的默认行为。
根据MySQL 关于 LAST_INSERT_ID 的文档:
LAST_INSERT_ID()返回一个 BIGINT UNSIGNED(64 位)值,表示 由于最近执行的 INSERT 语句而为AUTO_INCRMENT列 成功插入的
第一个自动生成的值。
很明显,它仅适用于auto_increment字段。
没有任何字段id_1和id_2被归因auto_increment。
由于这个原因,尽管您null在插入时作为这些字段的输入传递,但不会自动生成任何值并分配给它们。
更改表以设置auto_increment为这些字段之一id_x,然后开始插入值。需要注意的是,在插入期间将值显式传递给auto_increment字段将导致last_insert_id返回一个zero或最近自动生成的值,但不会返回NEW.id. 在插入过程中传递null或不选择auto_increment字段将触发该字段生成新值,并且last_insert_id可以选择并返回它。
以下示例演示了上述行为:
mysql> drop table if exists so_q27476005;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> create table so_q27476005( i int primary key );
Query OK, 0 rows affected (0.33 sec)
Run Code Online (Sandbox Code Playgroud)
以下语句显示auto_increment字段的下一个适用值。
mysql> select auto_increment
-> from information_schema.tables
-> where table_name='so_q27476005';
+----------------+
| auto_increment |
+----------------+
| NULL |
+----------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
让我们尝试null在字段中插入一个值。
mysql> insert into so_q27476005 values( null );
ERROR 1048 (23000): Column 'i' cannot be null
Run Code Online (Sandbox Code Playgroud)
上述语句失败,因为输入已进入not null primary key字段但未归因于auto_increment。仅对于auto_increment字段,您可以传递null输入。
现在让我们看看 的行为last_insert_id:
mysql> insert into so_q27476005 values( 1 );
Query OK, 1 row affected (0.04 sec)
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 0 |
+------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
由于输入是明确的,并且该字段不属于auto_increment,
因此调用last_insert_id结果为0。请注意,如果在同一数据库连接会话中insert对另一个表的任何其他字段进行了另一次调用,则这也可以是其他值。auto_increment
我们来看看表中的记录。
mysql> select * from so_q27476005;
+---+
| i |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
现在,让我们应用auto_increment到这个领域i。
mysql> alter table so_q27476005 change column i i int auto_increment;
Query OK, 1 row affected (0.66 sec)
Records: 1 Duplicates: 0 Warnings: 0
Run Code Online (Sandbox Code Playgroud)
以下语句显示auto_increment该字段的下一个适用值i。
mysql> select auto_increment
-> from information_schema.tables
-> where table_name='so_q27476005';
+----------------+
| auto_increment |
+----------------+
| 2 |
+----------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
您可以交叉检查蒸馏器last_insert_id是否相同。
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 0 |
+------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
让我们null在字段中插入一个值i。
mysql> insert into so_q27476005 values( null );
Query OK, 1 row affected (0.03 sec)
Run Code Online (Sandbox Code Playgroud)
虽然将 a 传递null给primary key字段,但它成功了,因为该字段归因于auto_increment。
让我们看看生成并插入了哪些值。
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 2 |
+------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
auto_increment该字段的下一个适用值i是:
mysql> select auto_increment
-> from information_schema.tables
-> where table_name='so_q27476005';
+----------------+
| auto_increment |
+----------------+
| 3 |
+----------------+
1 row in set (0.00 sec)
mysql> select * from so_q27476005;
+---+
| i |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
现在,让我们观察last_insert_id为字段给出显式输入时的结果。
mysql> insert into so_q27476005 values( 3 );
Query OK, 1 row affected (0.07 sec)
mysql> select * from so_q27476005;
+---+
| i |
+---+
| 1 |
| 2 |
| 3 |
+---+
3 rows in set (0.00 sec)
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 2 |
+------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
您可以看到last_insert_id由于显式输入而没有捕获该值。
但是,信息模式确实注册了下一个适用的值。
mysql> select auto_increment
-> from information_schema.tables
-> where table_name='so_q27476005';
+----------------+
| auto_increment |
+----------------+
| 4 |
+----------------+
1 row in set (0.08 sec)
Run Code Online (Sandbox Code Playgroud)
现在,让我们观察last_insert_id当字段输入是自动/隐式时的结果。
mysql> insert into so_q27476005 values( null );
Query OK, 1 row affected (0.10 sec)
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 4 |
+------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
希望这些细节对您有所帮助。