先说下使用mysql 的 SELECT LAST_INSERT_ID()这个sql语句的场景,就是我们向主键是自增的mysql数据表(简称user表)中insert一条记录后,我们期望 获取刚刚写入这条记录的id,因为某些场景下需要获得这个id去做其它的操作,所以很自然的想到了使用SELECT LAST_INSERT_ID() 这个sql语句来获取插入记录后返回的自增id,参考sql语句如下:
<insert id="insert" parameterClass="UserDO">
INSERT INTO user( user_id,user_nick,tel_phone,address,
status, user_type
,remark, gmt_create, gmt_modified)
VALUES ( #userId#, #userNick#, #telPhone#, #address#, #status#,
#userType#,
#remark#, now(), now())
<selectKey keyProperty="id" resultClass="java.lang.Long">
SELECT LAST_INSERT_ID() AS value
</selectKey>
</insert>
其中user表的主键是自增的id.
通过这种方式获取返回的自增id的确大多数情况下的确也能测试通过,所以测试的时候自己也很难发现问题,我就简单说下我碰到的情况:
问题1.有些时候调用Object id=getSqlMapClientTemplate().insert("UserDO.insert", userDO);这个语句返回的id返回的值是0,但是的确记录是写入到数据库user表中去了,这种情况直接导致我用返回值id大于0来判断 insert成功这个逻辑不准备,因为有的时候写入成功了也会返回0,这个问题不是每次都能重现,所以很诡异。
问题2.
有些时候调用Object id=getSqlMapClientTemplate().
insert("UserDO.insert", userDO);这个语句返回的id返回的值是大于0,但是用这个id去查询user表这条记录时确提示失败,原来是
<selectKey keyProperty="id" resultClass="java.lang.Long">
SELECT LAST_INSERT_ID() AS value
</selectKey>
这个语句的意思是返回最后一个写入数据库的id,但是在高并发多个数据表都有写入的情况,下,这个语句返回的就有可能是另外一张表刚刚写入的数据库id,这样根据这个id去查询就返回没有这个记录了
对于以上这两种情况我目前我使用的办法就是insert记录后不根据返回的id值来判断,而是用这个user表的唯一索引user_id去重新查一次user表来获取这个id,这种重新去查的方法基本可以满足大部分场景需求
写这篇文章主要有三个目的:
1.我踩到过这个坑,希望大家引以为鉴,因为测试的时候也比较难发现,希望大家不要犯类似错误
2.对于上面提到的问题1有时候会返回0的情况实在没想通,所以请各位大神帮我扫下盲
3.对于上面提到的解决办法,如果碰到没有设置唯一索引的情况,并且通过多个字段联合查询也不能唯一确定返回的记录是不是就是你刚刚写入的记录的这种情况下,是否有其它的方法可以尝试,在这方面是个新人,求各位大神多多指导!
摘自:http://www.atatech.org/article/detail/14015/0