mysql 中得到新插入数据的 id ,在 ibatis 中的应用 | 一亩三分地

J2EE

mysql 中得到新插入数据的 ID ,在 ibatis 中的应用

我们经常有这种需求,插入一条数据库记录时,需要马上得到这条记录的 AUTO_INCREMENT ID 。很多数据库有内置支持,mysql 中一直没有找到办法,以为没有内置支持呢,所以用个比较笨的办法,有朋友问我这个问题时,我也是说的这个:

select max(ID) from mytable


回最大的 id 。这个语句得与插入记录的语句在同一个“事务”里,如果用 jdbc 事务,应该一个 connection commit
里。在数据量不大时,应用当然是没有问题。 数据量非常大的情况我就不知道了,我认为应该是没有问题的。因为,一个“事务”就保证了 SQL
插入操作后与 SQL 取得 max(ID) 的操作之间,不可能再有别的数据库操作。 我是这样以为,但还是没有底。。。

今天无意中发现,mysql 还是有内置支持的,有专门的一个函数:

LAST_INSERT_ID([expr])

google 这个函数名称,找到英文或者中文的 mysql 参考手册都有详细的说明。文档说明也特别提到,用这个函数得到最新的 id ,操作也还是需要在与插入操作同一个 connection 范围内。应该说与原来的作法是类似的。


有一点意外的发现就是,ibatis 里的 sqlmap insert 操作,竟然返回新插入数据的自增 id
。这样我在程序里就不需要用二个独立的方法了,一个 sqlmap insert 就搞定了,真是爽。当然 sqlmap insert SQL
写法有不同:

<insert id="insertTopic" parameterClass="topic">
insert into TOPIC (FORUM_ID, USERID, TITLE, SUMMARY, CREATE_TIME)
values (#forumId#, #userid#, #title#, #summary#, now())
<selectKey resultClass="string" keyProperty="id">
select last_insert_id() as ID from TOPIC limit 1
</selectKey>
</insert>

现在我们来注意一下这行 select last_insert_id() as ID from TOPIC limit 1 ,不同的数据库,这地方有不同,都有自己特别的内置实现。请又特别注意 limit 1 这地方,看文档应该是返回一条记录的,就是返回 id 呀,但实际应用中我发现,竟然返回了 n 条记录。没有办法,我只有限制记录条数为 1 ,但结果也是对的。不知道这个算不算 mysql 的 bug 。


果大家仔细看 last_insert_id() 这个函数的文档,他举了个用这个函数实现 sequence
的例子,感觉很值得引起注意,暂时我是用不着,但有需要用得着的时候。可能有这样一种需要:需要得到自增 id ,这个 id
我可能是用作数据库表的主键,也可能有别的用途。一般的想法,好像只有在数据库里写个存储过程,反正我是没有写过,关键是需要考虑多用户并发。。。

用 last_insert_id() 函数这样来模拟一个 sequence 实现:

mysql> CREATE TABLE sequence (id INT NOT NULL);
mysql> INSERT INTO sequence VALUES (0);
mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
因为“如果 expr 被作为一个参数传递给
LAST_INSERT_ID(),那么函数将返回这个参数的值,并且被设置为 LAST_INSERT_ID()
返回的下一个值
”,这样每次 update sequence 后,id 肯定是自增过了,关键是这个数据库级的支持,不需要你再去考虑多用户并发问题。