转自: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. 深度学习基础系列(三)| sigmoid、tanh和relu激活函数的直观解释

    常见的激活函数有sigmoid.tanh和relu三种非线性函数,其数学表达式分别为: sigmoid: y = 1/(1 + e-x) tanh: y = (ex - e-x)/(ex + e-x) ...

  2. java反射,代码优化

    java的反射机制属实强大,能解决好些问题 在接手别人写的代码的时候,有一个bean类的get方法特别low,我都看不下去 重复代码写五遍,我都觉得太不合理.之后将其中代码抽取出来修改了下. publ ...

  3. Web应用类型扫描识别工具WhatWeb

    Web应用类型扫描识别工具WhatWeb   WhatWeb是一款Kali Linux预安装的Web扫描工具.它使用Ruby语言编写.该工具可以扫描网站,获取该网站的各类信息,如所使用的CMS.博客平 ...

  4. bzoj5299: [Cqoi2018]解锁屏幕

    题目链接 bzoj 5299: [Cqoi2018]解锁屏幕 题解 很水的装压dp,相信没人需要看题解.... dp[i][j]表示状态为i最后一个到的点为j,然后转移就很好写了 不过 我读入优化没读 ...

  5. BZOJ1030 [JSOI2007]文本生成器(AC自动机)

    做到了AC自动机的题目,复习了一下AC自动机,学习了黄学长代码,这个题呢,我们可以模拟在AC自动机上的操作,dp数组f[i][j]表示前i个字符,我们在AC自动机上处在j号节点的方案数. 我们可以计算 ...

  6. 【8.31校内测试】【找规律二分】【DP】【背包+spfa】

    打表出奇迹!表打出来发现了神奇的规律: 1 1 2 2 3 4 4 4 5 6 6 7 8 8 8 8 9 10 10 11 12 12 12 13 14 14 15 16 16 16 16 16.. ...

  7. 权限验证AuthorizeAttribute

    /// <summary> /// 权限验证属性. /// </summary> public class AuthorizeExAttribute : AuthorizeAt ...

  8. bzoj 1303: [CQOI2009]中位数图 数学

    1303: [CQOI2009]中位数图 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/ ...

  9. [转]web服务器apache架构与原理 &apache 监控

    web服务器                                                                                在开始了解Apache前,我 ...

  10. JVM调优总结 -Xms -Xmx -Xmn -Xss等

                  首先介绍一下新生代.老年代.所谓的新生代和老年代是针对于分代收集算法来定义的,新生代又分为Eden和Survivor两个区.加上老年代就这三个区.数据会首先分配到Eden区 ...