`

关于使用mysql的 SELECT LAST_INSERT_ID() 语句碰到的问题

 
阅读更多

   先说下使用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
分享到:
评论
9 楼 Master-Gao 2017-05-09  
legend11 写道
我测试也返回1,搜索了半天,看到这里才恍然大悟:
mapper接口返回值依然是成功插入的记录数,但不同的是主键值已经赋值到领域模型实体的id中了
另:最新的要把resultClass改成resultType


正解啊,从直接理解是错的,加那段代码本质上也不会返回新插入数据的id,返回的还是insert语句执行后受影响的行数,只是会把id赋值到领域模型实体中
8 楼 高军威 2017-01-20  
  最终解决方案呢?
7 楼 legend11 2016-04-24  
我测试也返回1,搜索了半天,看到这里才恍然大悟:
mapper接口返回值依然是成功插入的记录数,但不同的是主键值已经赋值到领域模型实体的id中了
另:最新的要把resultClass改成resultType
6 楼 diuse 2016-04-09  
我也遇到了同样的问题,使用last_insert_id(),返回值有两种,一种是0,一种是插入id-1。没有搞明白是什么原因。后面使用事务包了一下插入就正常了。
我当时是使用id作为了业务主键,插入后必须返回id供用户删除用。
所以返回0或者id-1都不能满足应用。
当时想的另外一种解决方式是自己弄主键,插入只要不报异常就是成功,这样也是比较简单的,麻烦的就是自己控制主键生成
5 楼 kevin2234 2015-10-14  
我跟3楼一样都是返回1,不知道为什么???用4楼的方法还是不行,会报错。求求求解::
4 楼 focus2008 2015-09-17  
要改成这样:
<insert id="insert" parameterClass="UserDO">
<selectKey keyProperty="id" resultClass="java.lang.Long">

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())

SELECT LAST_INSERT_ID() AS value
</selectKey>
</insert>

让 <selectKey> 包含住整个insert 语句:
<selectKey keyProperty="id" resultClass="java.lang.Long">
insert ....
SELECT LAST_INSERT_ID() AS value
</selectKey>
3 楼 wnjustdoit 2015-05-28  
Super_GoodMan 写道
 
可以用以下这种方式,亲测过很好用!
<insert id="add" parameterType="vo.Category" useGeneratedKeys="true" keyProperty="id">
insert into category (name_zh, parent_id,
show_order, delete_status, description
)
values (#{nameZh,jdbcType=VARCHAR},
#{parentId,jdbcType=SMALLINT},
#{showOrder,jdbcType=SMALLINT},
#{deleteStatus,jdbcType=BIT},
#{description,jdbcType=VARCHAR}
)
</insert>

Super_GoodMan 写道
 
可以用以下这种方式,亲测过很好用!
<insert id="add" parameterType="vo.Category" useGeneratedKeys="true" keyProperty="id">
insert into category (name_zh, parent_id,
show_order, delete_status, description
)
values (#{nameZh,jdbcType=VARCHAR},
#{parentId,jdbcType=SMALLINT},
#{showOrder,jdbcType=SMALLINT},
#{deleteStatus,jdbcType=BIT},
#{description,jdbcType=VARCHAR}
)
</insert>


你好,我的每次都返回1,是什么情况呢
2 楼 Super_GoodMan 2015-05-28  
 
可以用以下这种方式,亲测过很好用!
<insert id="add" parameterType="vo.Category" useGeneratedKeys="true" keyProperty="id">
insert into category (name_zh, parent_id,
show_order, delete_status, description
)
values (#{nameZh,jdbcType=VARCHAR},
#{parentId,jdbcType=SMALLINT},
#{showOrder,jdbcType=SMALLINT},
#{deleteStatus,jdbcType=BIT},
#{description,jdbcType=VARCHAR}
)
</insert>
1 楼 zzp1994114 2015-05-27  
挺好,就是需要你这种人

相关推荐

    Mysql中LAST_INSERT_ID()的函数使用详解

    3. **多行插入**:如果你在一个INSERT语句中插入了多行数据,LAST_INSERT_ID()只会返回第一行数据生成的自增ID。这是为了简化在主从复制环境中保持一致性,因为在复制过程中,多行插入语句会被分别处理,每行都会...

    解决Hibernate JPA中insert插入数据后自动执行select last_insert_id()

    在使用Hibernate JPA进行数据操作时,我们可能会遇到一个特定的情况,即在执行完插入(insert)操作后,系统会自动执行一个`select last_insert_id()`的查询来获取刚刚生成的自增主键值。这个问题在Spring MVC集成...

    MYSQL 小技巧 -- LAST_INSERT_ID

    - 有人为了获取最近插入的ID值,可能会采用SELECT MAX(id) FROM 表名的SQL语句来替代LAST_INSERT_ID() 或mysql_insert_id()。 - 然而,这种方法是非线程安全的,即在多线程环境下,可能存在无法获取到最新插入记录...

    MYSQL 小技巧 — LAST_INSERT_ID

    标题提到的"MYSQL 小技巧 — LAST_INSERT_ID"着重讨论了MySQL中获取自增ID的两种方法:`LAST_INSERT_ID()`和`mysql_insert_id()`的区别以及它们在不同情况下的适用性。 首先,`LAST_INSERT_ID()`函数是MySQL提供的...

    使用MySQL的LAST_INSERT_ID来确定各分表的唯一ID值

    为了解决这个问题,我们可以利用MySQL的`LAST_INSERT_ID()`函数来生成并追踪各分表的唯一ID。 首先,我们需要创建一个单独的表,例如`ticket_mutex`,用于存储不同业务的ID值。这个表包含两个字段:`name`用于标识...

    PHP获取MySql新增记录ID值的3种方法

    当遇到`bigint`类型的ID时,可以使用MySQL的内置函数`LAST_INSERT_ID()`来解决`mysql_insert_id()`的问题,如下所示: ```php $result = mysql_query("SELECT LAST_INSERT_ID()", $link); ``` `LAST_INSERT_ID...

    mysql中实现sequence.pdf

    在某些数据库系统中,可以通过内置的函数来实现这一点,而在MySQL中,我们可以使用`LAST_INSERT_ID()`函数来达到目的。`LAST_INSERT_ID()`函数返回的是最后通过`INSERT`语句产生的`AUTO_INCREMENT`值。为了确保正确...

    mysql的插入问题 怎么获得自动增长的ID

    - 如果你的应用环境中允许使用`LAST_INSERT_ID()`函数,可以通过执行如下SQL语句来获取最后插入记录的ID。 ```java Statement stmt = connection.createStatement(); stmt.executeUpdate("INSERT INTO test_...

    Vocabulary_python_mySQL.rar_MYSQL_python mysql_python MySQL_p

    cursor.execute(query, (employee_id,)) for (first_name, last_name) in cursor: print(f"{first_name} {last_name}") ``` 在执行完SQL操作后,记得关闭游标和连接以释放资源: ```python cursor.close() cnx....

    PHP用mysql_insert_id()函数获得刚插入数据或当前发布文章的ID

    `mysql_insert_id()`函数就是为了解决这一问题而设计的。它允许开发者在成功执行一个INSERT语句后,获取到自增ID,这对于追踪和管理数据库中的记录至关重要。 **前言** 在处理数据库事务时,特别是在内容管理系统或...

    利用mysql事务特性实现并发安全的自增ID示例

    通过`UPDATE`语句将ID设置为其自身的值加1,然后使用`SELECT LAST_INSERT_ID();`获取新生成的ID。`LAST_INSERT_ID()`函数返回的是最后一次`INSERT`操作生成的ID,且只针对当前连接,因此在并发环境中可以确保每个...

    解析sql中得到刚刚插入的数据的id

    之后,`SELECT LAST_INSERT_ID();` 将返回2,这是第一条插入记录'aaaa'的ID,而不是最后一条记录'cccc'的ID。 另外,有些数据库系统,如SQL Server,使用`@@IDENTITY`变量来获取最近插入的自动递增ID。与`LAST_...

    Mysql(序列/ID)生成方案

    一种可能的解决方案是使用`LAST_INSERT_ID()`函数配合`SELECT...FOR UPDATE`语句。当多个并发线程尝试获取新的ID时,每个线程都会锁定表中的特定行,然后通过`LAST_INSERT_ID()`获取当前的ID并增加它。这样可以确保...

    mysql取得自动增长的主键值

    - **标准方法:** 使用`INSERT`语句插入数据后,可以通过`LAST_INSERT_ID()`函数或`getGeneratedKeys()`方法来获取刚插入记录的自增ID。 - **示例代码:** 下面的Java示例展示了如何使用JDBC API来插入一条记录并...

    dataBase_Test_swimmingqbm_Qt操作MySQL_QT_qtmysql_MYSQL_

    例如,使用`QSqlQuery::exec()`方法执行INSERT、UPDATE、DELETE或SELECT语句。对于增删改操作,记得在事务中进行,以确保数据的完整性。 4. **增添数据**: 通过`INSERT INTO`语句向表中添加新记录。例如,`query....

Global site tag (gtag.js) - Google Analytics