BEGIN; COMMIT;的替代方法因为交易会影响我使用LAST_INSERT_ID()的能力?

时间:2019-04-25 19:54:16

标签: mysql database

我需要每个条目INSERT INTO多个表,并且为了安全地执行此操作,我决定将整个语句设置为TRANSACTION。但是,我的代码依赖于LAST_INSERT_ID()随每个INSERT INTO进行更新,并且似乎LAST_INSERT_ID()仅按每个TRANSACTION 更新。因此,我要么需要替代典型的START TRANSACTION; COMMIT;格式,或者我需要LAST_INSERT_ID()的替代方案,但仍然可以实现相同的目标。

yearandpage 都具有自动递增的主键,而这些键是 personinschoolyearbook 表中的外键。 >

导致我问这个问题的原始问题是,我有两个带有主键的表和一个引用这两个表的关系表。如何通过一个数据条目同时更新所有三个?我研究了级联引用完整性,这会使我的外键自动更新,但是我认为这不起作用,因为我的关系表具有必须手动插入的非外键值(状态)

START TRANSACTION;
INSERT INTO person (firstname, middlename, lastname, maidenname)
VALUES ('Test2fname', NULL, 'Test2lname', NULL);
INSERT INTO personinschoolyearbook (personid, yearandpageid, status)
VALUES (LAST_INSERT_ID(), 0, 'Test2status'); --The zero is a placeholder, to be replaced with the primary key id that will be created in the next INSERT INTO
SELECT @personid := LAST_INSERT_ID();
INSERT INTO yearandpage (yearincluded, page, schoolid, url) --Here is where the LAST_INSERT_ID() should update but doesn't
VALUES (0000, 00, 2, 'Test2url');
UPDATE personinschoolyearbook SET yearandpageid=LAST_INSERT_ID()
WHERE personinschoolyearbook.personid = @personid;
COMMIT;

现在,LAST_INSERT_ID()的值未更改,而在我的关系表 personinschoolyearbook 中,应具有从 yearandpage 中获取的新ID的列改为与从人员获取的ID相同。

2 个答案:

答案 0 :(得分:1)

LAST_INSERT_ID()始终报告当前会话中生成的最新自动增量值。这不受交易的限制。您可以启动一个新事务,而LAST_INSERT_ID()仍将返回最新的自动增量值。

mysql> create table foo (id serial primary key);

mysql> begin;

mysql> insert into foo () values ();
Query OK, 1 row affected (0.01 sec)

mysql> select last_insert_id() into @id1;
Query OK, 1 row affected (0.00 sec)

mysql> insert into foo () values ();
Query OK, 1 row affected (0.00 sec)

mysql> select last_insert_id() into @id2;
Query OK, 1 row affected (0.00 sec)

mysql> select @id1, @id2;
+------+------+
| @id1 | @id2 |
+------+------+
|    1 |    2 |
+------+------+

如果将值插入具有自动增量的表中,但是指定了非零值,从而阻止了自动增量生成新的ID,则它也不会更改LAST_INSERT_ID()返回的值;

mysql> insert into foo set id = 10;
Query OK, 1 row affected (0.01 sec)

mysql> select * from foo;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
| 10 |
+----+

mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|                3 |
+------------------+

如果您的主键不是自动插入键,则INSERT不会更改LAST_INSERT_ID()返回的值,该值是任何自动操作在当前会话中生成的最新ID的值。 inc,即使是用于另一个表或另一个事务中。

mysql> create table bar (id bigint primary key); -- not AUTO_INCREMENT

mysql> insert into bar set id = 42;
Query OK, 1 row affected (0.01 sec)

mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|                3 |
+------------------+

答案 1 :(得分:0)

如Bill Karwin的回答所述,LAST_INSERT_ID()不受交易影响。它没有更新的原因是因为当我进入INSERT INTO yearandpage 时,如果该条目已经存在,则不会输入任何数据,因此LAST_INSERT_ID()不会有任何值。 Uueerdo提出了这可能是问题所在,但是由于我在运行代码时以某种方式错过了重复的输入错误,因此我认为INSERT INTO可以正常工作。

重复的条目是造成我的问题的原因,需要在项目中解决,因此,为了解决此问题,我使用了ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id),您可以在{{ 3}}

这是我的最终代码:

START TRANSACTION;
INSERT INTO person (firstname, middlename, lastname, maidenname)
VALUES ('Test2fname', NULL, 'Test2lname', NULL);
INSERT INTO personinschoolyearbook (personid, yearandpageid, status)
VALUES (LAST_INSERT_ID(), 0, 'Test2status');
SELECT @personid := LAST_INSERT_ID();
INSERT INTO yearandpage (yearincluded, page, schoolid, url)
VALUES (0000, 00, 2, 'Test2url') 
ON DUPLICATE KEY UPDATE yearandpageid = LAST_INSERT_ID(yearandpageid);
UPDATE personinschoolyearbook SET yearandpageid=LAST_INSERT_ID()
WHERE personinschoolyearbook.personid = @personid;
COMMIT;