转自:http://blog.csdn.net/ultrani/article/details/9351573

作者已经写的非常好了,我不废话了,直接转载收藏:

通常我们在应用中对mysql执行了insert操作后,需要获取插入记录的自增主键。本文将介绍java环境下的4种方法获取insert后的记录主键auto_increment的值:

  1. 通过JDBC2.0提供的insertRow()方式
  2. 通过JDBC3.0提供的getGeneratedKeys()方式
  3. 通过SQL select LAST_INSERT_ID()函数
  4. 通过SQL @@IDENTITY 变量

1. 通过JDBC2.0提供的insertRow()方式

自jdbc2.0以来,可以通过下面的方式执行。

Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, // 创建Statement
java.sql.ResultSet.CONCUR_UPDATABLE);
stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial");
stmt.executeUpdate( // 创建demo表
"CREATE TABLE autoIncTutorial ("
+ "priKey INT NOT NULL AUTO_INCREMENT, "
+ "dataField VARCHAR(64), PRIMARY KEY (priKey))");
rs = stmt.executeQuery("SELECT priKey, dataField " // 检索数据
+ "FROM autoIncTutorial");
rs.moveToInsertRow(); // 移动游标到待插入行(未创建的伪记录)
rs.updateString("dataField", "AUTO INCREMENT here?"); // 修改内容
rs.insertRow(); // 插入记录
rs.last(); // 移动游标到最后一行
int autoIncKeyFromRS = rs.getInt("priKey"); // 获取刚插入记录的主键preKey
rs.close();
rs = null;
System.out.println("Key returned for inserted row: "
+ autoIncKeyFromRS);
} finally {
// rs,stmt的close()清理
}

优点:早期较为通用的做法

缺点:需要操作ResultSet的游标,代码冗长。

2. 通过JDBC3.0提供的getGeneratedKeys()方式

Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_UPDATABLE);
// ...
// 省略若干行(如上例般创建demo表)
// ...
stmt.executeUpdate(
"INSERT INTO autoIncTutorial (dataField) "
+ "values ('Can I Get the Auto Increment Field?')",
Statement.RETURN_GENERATED_KEYS); // 向驱动指明需要自动获取generatedKeys!
int autoIncKeyFromApi = -;
rs = stmt.getGeneratedKeys(); // 获取自增主键!
if (rs.next()) {
autoIncKeyFromApi = rs.getInt();
} else {
// throw an exception from here
}
rs.close();
rs = null;
System.out.println("Key returned from getGeneratedKeys():"
+ autoIncKeyFromApi);
} finally { ... }

这种方式只需要2个步骤:

1. 在executeUpdate时激活自动获取key;
2.调用Statement的getGeneratedKeys()接口
优点:
1. 操作方便,代码简洁
2. jdbc3.0的标准
3. 效率高,因为没有额外访问数据库
 
这里补充下,
a.在jdbc3.0之前,每个jdbc driver的实现都有自己获取自增主键的接口。在mysql jdbc2.0的driver org.gjt.mm.mysql中,getGeneratedKeys()函数就实现在org.gjt.mm.mysql.jdbc2.Staement.getGeneratedKeys()中。这样直接引用的话,移植性会有很大影响。JDBC3.0通过标准的getGeneratedKeys很好的弥补了这点。
b.关于getGeneratedKeys(),官网还有更详细解释:OracleJdbcGuide

3. 通过SQL select
LAST_INSERT_ID()

Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
// ...
// 省略建表
// ...
stmt.executeUpdate(
"INSERT INTO autoIncTutorial (dataField) "
+ "values ('Can I Get the Auto Increment Field?')");
int autoIncKeyFromFunc = -;
rs = stmt.executeQuery("SELECT LAST_INSERT_ID()"); // 通过额外查询获取generatedKey
if (rs.next()) {
autoIncKeyFromFunc = rs.getInt();
} else {
// throw an exception from here
}
rs.close();
System.out.println("Key returned from " +
"'SELECT LAST_INSERT_ID()': " +
autoIncKeyFromFunc);
} finally {...}

这种方式没什么好说的,就是额外查询一次函数LAST_INSERT_ID().

优点:简单方便
缺点:相对JDBC3.0的getGeneratedKeys(),需要额外多一次数据库查询。
 
补充:
1. 这个函数,在mysql5.5手册的定义是:“returns a BIGINT (64-bit) value representing the first automatically generated value successfully inserted for an AUTO_INCREMENT column as a result of the most recently executed INSERT statement.”。文档点此
2. 这个函数,在connection维度上是“线程安全的”。就是说,每个mysql连接会有个独立保存LAST_INSERT_ID()的结果,并且只会被当前连接最近一次insert操作所更新。也就是2个连接同时执行insert语句时候,分别调用的LAST_INSERT_ID()不会相互覆盖。举个栗子:连接A插入表后LAST_INSERT_ID()返回100,连接B插入表后LAST_INSERT_ID()返回101,但是连接A重复执行LAST_INSERT_ID()的时候,始终返回100,而不是101。这个可以通过监控mysql连接数和执行结果来验证,这里不详述实验过程。
3. 在上面那点的基础上,如果在同一个连接的前提下同时执行insert,那可能2次操作的返回值会相互覆盖。因为LAST_INSERT_ID()的隔离程度是连接级别的。这点,getGeneratedKeys()是可以做的更好,因为getGeneratedKeys()是statement级别的。同个connection的多次statement,getGeneratedKeys()是不会被相互覆盖。

4. 通过SQL SELECT @@IDENTITY

这个方式和LAST_INSERT_ID()效果是一样的。官网文档如此表述:“This variable is a synonym for the last_insert_id variable. It exists for compatibility with other database systems. You can read its value with SELECT @@identity, and set it using SET identity.” 文档点此
 
重要补充:
无论是SELECT LAST_INSERT_ID()还是SELECT
@@IDENTITY,对于一条insert语句插入多条记录,永远只会返回第一条插入记录的generatedKey.如:
INSERT INTO t VALUES
-> (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');

LAST_INSERT_ID(), @@IDENTITY都只会返回'Mary'所在的那条记录的generatedKey

小结

所以,最好还是通过JDBC3 提供的getGeneratedKeys()函数来获取insert记录的主键。不但简单,而且效率高。
 
在mybatis中,就有相关设置: 
<insert id="save" parameterType="MappedObject" useGeneratedKeys="true" keyProperty="id">
</insert>

可参考mybatis文档:sqlmap-xml

参考资料

MYSQL获取自增主键【4种方法】(转)的更多相关文章

  1. MYSQL获取自增ID的四种方法

    MYSQL获取自增ID的四种方法 1. select max(id) from tablename 2.SELECT LAST_INSERT_ID() 函数 LAST_INSERT_ID 是与tabl ...

  2. DBS-MySQL:MYSQL获取自增ID的四种方法

    ylbtech-DBS-MySQL:MYSQL获取自增ID的四种方法 1.返回顶部 1. 1. select max(id) from tablename 2.SELECT LAST_INSERT_I ...

  3. MYSQL获取自增主键【4种方法】

    通常我们在应用中对mysql执行了insert操作后,需要获取插入记录的自增主键.本文将介绍java环境下的4种方法获取insert后的记录主键auto_increment的值: 通过JDBC2.0提 ...

  4. mysql 获取自增主键

    MyBatis 3.2.6插入时候获取自增主键方法有二 以MySQL5.5为例: 方法1: <insert id="insert" parameterType="P ...

  5. 【JAVA - SSM】之MyBatis插入数据后获取自增主键

    很多时候,我们都需要在插入一条数据后回过头来获取到这条数据在数据表中的自增主键,便于后续操作.针对这个问题,有两种解决方案: (1)先插入,后查询.我们可以先插入一条数据,然后根据插入的数据的各个字段 ...

  6. mybatis框架(6)---mybatis插入数据后获取自增主键

    mybatis插入数据后获取自增主键 首先理解这就话的意思:就是在往数据库表中插入一条数据的同时,返回该条数据在数据库表中的自增主键值. 有什么用呢,举个例子: 你编辑一条新闻,同时需要给该新闻打上标 ...

  7. Mybatis学习笔记4 - 获取自增主键的值

    获取自增主键的值:mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys():useGeneratedKeys="true&qu ...

  8. 深入分析Mybatis 使用useGeneratedKeys获取自增主键

    摘要 我们经常使用useGenerateKeys来返回自增主键,避免多一次查询.也会经常使用on duplicate key update,来进行insertOrUpdate,来避免先query 在i ...

  9. 【JavaEE】之MyBatis插入数据后获取自增主键

    很多时候,我们都需要在插入一条数据后回过头来获取到这条数据在数据表中的自增主键,便于后续操作.针对这个问题,有两种解决方案: 先插入,后查询.我们可以先插入一条数据,然后根据插入的数据的各个字段值,再 ...

随机推荐

  1. 消息中间件ActiveMQ使用详解

    消息中间件ActiveMQ使用详解 一.消息中间件的介绍 介绍 ​ 消息队列 是指利用 高效可靠 的 消息传递机制 进行与平台无关的 数据交流,并基于 数据通信 来进行分布式系统的集成. 特点(作用) ...

  2. Java常用工具类之时间转换(注释乱码,全)

    package com.wazn.learn.util; import java.text.ParseException; import java.text.SimpleDateFormat; imp ...

  3. NOIP 初赛笔记

    // zj蒟蒻瑟瑟发抖.. // 停课了.要好好努力!——10月8日8:29于机房 1. 1946 年 美国 -> 第一台计算机 2. 真空电子管 -> 晶体管 -> 集成 -> ...

  4. luogu P4115 Qtree4

    题目链接 luogu P4115 Qtree4 题解 动态点分治,和上一题一样.同样三个堆.就是带权,用边权替换深度就好 为什么要单独写这个题解呢,因为我卡常卡了一天....据说树剖比rmq快? 在第 ...

  5. [BZOJ1559][JSOI2009]密码(AC自动机)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1559 2009年的省选题虽然比起现在简单了不少,但对我来说还是很有挑战性的. 首先对于这种多串匹配问 ...

  6. HDU1429 胜利大逃亡 状压bfs

    http://acm.hdu.edu.cn/viewcode.php?rid=22225154 因为总共a-j有10种钥匙,所以可以把有没有钥匙的状态压到一个int数里,然后dfs. 昨天状态特别不好 ...

  7. Python字典树实现

    class Trie: # word_end = -1 def __init__(self): """ Initialize your data structure he ...

  8. Scala 元组

    与列表一样,元组也是不可变的,但与列表不同的是元组可以包含不同类型的元素. 元组的值是通过将单个的值包含在圆括号中构成的.例如: val t = (1, 3.14, "Fred") ...

  9. 配置nginx虚拟目录配置文件支持tp的pathinfo

    lnmp自带的包不好用, 经测试,在相应的conf文件加入这句话即可: location / { if (!-e $request_filename) { rewrite ^(.*)$ /index. ...

  10. 思科DCHP解决方案

    DHCP功能平时用的不算少,而且本人的几乎所有的DHCP功能都是在交换机上实现的,虽然也可以通过PC实现,而且PC的DHCP Server功能还更完善,比如可以不受DHCP作用域的限制.IP分配情况直 ...