mysql插入数据后返回自增ID的方法
 
mysql和oracle插入的时候有一个很大的区别是,oracle通过获取序列的方式得到主键,mysql本身有一个列可以做自增长字段,mysql在插入一条数据后,如何能获得到这个自增id的值呢?

 方法1:使用last_insert_id

mysql> SELECT LAST_INSERT_ID();

产生的ID 每次连接后保存在服务器中。这意味着函数向一个给定客户端返回的值是该客户端产生对影响AUTO_INCREMENT列的最新语句第一个 AUTO_INCREMENT值的。这个值不能被其它客户端影响,即使它们产生它们自己的 AUTO_INCREMENT值。这个行为保证了你能够找回自己的 ID 而不用担心其它客户端的活动,而且不需要加锁或处理。 
 
    每次mysql_query操作在mysql服务器上可以理解为一次“原子”操作, 写操作常常需要锁表的, 是mysql应用服务器锁表不是我们的应用程序锁表。
 
    值得注意的是,如果你一次插入了多条记录,这个函数返回的是第一个记录的ID值
    因为LAST_INSERT_ID是基于Connection的,只要每个线程都使用独立的Connection对象,LAST_INSERT_ID函数 将返回该Connection对AUTO_INCREMENT列最新的insert or update*作生成的第一个record的ID。这个值不能被其它客户端(Connection)影响,保证了你能够找回自己的 ID 而不用担心其它客户端的活动,而且不需要加锁。使用单INSERT语句插入多条记录,  LAST_INSERT_ID返回一个列表。
    LAST_INSERT_ID 是与table无关的,如果向表a插入数据后,再向表b插入数据,LAST_INSERT_ID会改变。
 
方法2:使用max(id)
 
使用last_insert_id是基础连接的,如果换一个窗口的时候调用则会一直返回10
如果不是频繁的插入我们也可以使用这种方法来获取返回的id值

select max(id) from user;

这个方法的缺点是不适合高并发。如果同时插入的时候返回的值可能不准确。
 
方法3:创建一个存储过程,在存储过程中调用先插入再获取最大值的操作

​
DELIMITER $$
DROP PROCEDURE IF EXISTS `test` $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `test`(in name varchar(100),out oid int)
BEGINinsert into user(loginname) values(name);select max(id) from user into oid;select oid;
END $$
DELIMITER ;
call test('gg',@id);​

方法4:使用@@identity

select @@IDENTITY

@@identity是表示的是最近一次向具有identity属性(即自增列)的表插入数据时对应的自增列的值,是系统定 义的全局变量。一般系统定义的全局变量都是以@@开头,用户自定义变量以@开头。比如有个表A,它的自增列是id,当向A表插入一行数据后,如果插入数据 后自增列的值自动增加至101,则通过select @@identity得到的值就是101。使用@@identity的前提是在进行insert操作后,执行select @@identity的时候连接没有关闭,否则得到的将是NULL值。

方法5:使用getGeneratedKeys()

Connection conn = ;
Serializable ret = null;
PreparedStatement state = .;
ResultSet rs=null;
try {state.executeUpdate();rs = state.getGeneratedKeys();if (rs.next()) {ret = (Serializable) rs.getObject(1);}
} catch (SQLException e) {
}
return ret;

总结一下,在mysql中做完插入之后获取id在高并发的时候是很容易出错的。另外last_insert_id虽然是基于session的但是不知道为什么没有测试成功。
     
方法6:selectkey:

其实在ibtias框架里使用selectkey这个节点,并设置insert返回值的类型为integer,就可以返回这个id值。

SelectKey在Mybatis中是为了解决Insert数据时不支持主键自动生成的问题,他可以很随意的设置生成主键的方式。

不管SelectKey有多好,尽量不要遇到这种情况吧,毕竟很麻烦。

selectKey Attributes
属性 描述
keyProperty selectKey 语句结果应该被设置的目标属性。
resultType 结果的类型。MyBatis 通常可以算出来,但是写上也没有问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。
order 这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素-这和如 Oracle 数据库相似,可以在插入语句中嵌入序列调用。
statementType 和前面的相 同,MyBatis 支持 STATEMENT ,PREPARED 和CALLABLE 语句的映射类型,分别代表 PreparedStatement 和CallableStatement 类型。

SelectKey需要注意order属性,像Mysql一类支持自动增长类型的数据库中,order需要设置为after才会取到正确的值。

像Oracle这样取序列的情况,需要设置为before,否则会报错。

另外在用Spring管理事务时,SelectKey和插入在同一事务当中,因而Mysql这样的情况由于数据未插入到数据库中,所以是得不到自动增长的Key。取消事务管理就不会有问题。

下面是一个xml和注解的例子,SelectKey很简单,两个例子就够了:

<insert id="insert" parameterType="map">  insert into table1 (name) values (#{name})  <selectKey resultType="java.lang.Integer" keyProperty="id">  CALL IDENTITY()  </selectKey>
</insert>

上面xml的传入参数是map,selectKey会将结果放到入参数map中。用POJO的情况一样,但是有一点需要注意的是,keyProperty对应的字段在POJO中必须有相应的setter方法,setter的参数类型还要一致,否则会报错。

@Insert("insert into table2 (name) values(#{name})")
@SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)
int insertTable2(Name name); 

上面是注解的形式。

方法:7:使用<insert中的useGeneratedKeys 和keyProperty 两个属性

1.在Mybatis Mapper文件中添加属性“useGeneratedKeys”和“keyProperty”,其中keyProperty是Java对象的属性名,而不是表格的字段名

<insert id="insert" parameterType="Spares"     useGeneratedKeys="true" keyProperty="id">    insert into system(name) values(#{name})
</insert> 

2.Mybatis执行完插入语句后,自动将自增长值赋值给对象systemBean的属性id。因此,可通过systemBean对应的getter方法获取!

int count = systemService.insert(systemBean);    int id = systemBean.getId(); //获取到的即为新插入记录的ID 

【注意事项】

1.Mybatis Mapper 文件中,“useGeneratedKeys”和“keyProperty”必须添加,而且keyProperty一定得和java对象的属性名称一直,而不是表格的字段名

2.java Dao中的Insert方法,传递的参数必须为java对象,也就是Bean,而不能是某个参数。

[其他方法].1.  通过JDBC2.0提供的insertRow()方式

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

Statement stmt = null;
ResultSet rs = null;
try {stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,  // 创建Statementjava.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");                        // 获取刚插入记录的主键preKeyrs.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 = -1;rs = stmt.getGeneratedKeys();                                  // 获取自增主键!if (rs.next()) {autoIncKeyFromApi = rs.getInt(1);}  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

参考资料

1.https://www.cnblogs.com/duanxz/p/3862356.html

2.https://blog.csdn.net/UltraNi/article/details/9351573

MySQL获取自增主键Id相关推荐

  1. mysql 获取自增主键

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

  2. Java代码TkMyBatis通用Mapper中新增数据时同时获取自增主键ID,与适用uuid 做主键时获取 id

    一 . MyBatis mapper.xml文件中在xml 1.   加入 这句 :useGeneratedKeys="true" keyProperty="ID&quo ...

  3. Mysql和Oracle获取自增主键

    mysql <!-- parameterType:参数类型,可以省略,      获取自增主键的值:         mysql支持自增主键,自增主键值的获取,mybatis也是利用statem ...

  4. MYSQL自增主键ID重置

    MYSQL在创建一个带有自增主键ID的表时,通常在删除数据时,导致自增主键不连续了.使用下面的SQL脚本可以重置主键. -- 1.重置已有数据主键 SET @rownum = 0; UPDATE ta ...

  5. 为什么 MySQL 的自增主键不单调也不连续

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 转自:真没什么逻辑/Draveness 当我们在使用关系型数据库时 ...

  6. 无法去掉自增标识_为什么 MySQL 的自增主键不单调也不连续

    为什么这么设计(Why's THE Design)是一系列关于计算机领域中程序设计决策的文章,我们在这个系列的每一篇文章中都会提出一个具体的问题并从不同的角度讨论这种设计的优缺点.对具体实现造成的影响 ...

  7. mysql自增_面试官:为什么 MySQL 的自增主键不单调也不连续?

    为什么这么设计(Why's THE Design)是一系列关于计算机领域中程序设计决策的文章,我们在这个系列的每一篇文章中都会提出一个具体的问题并从不同的角度讨论这种设计的优缺点.对具体实现造成的影响 ...

  8. mybatis3.1-[topic-16-17]-映射文件_增删改查_insert_获取自增主键的值

    笔记要点 出错分析与总结 /**测试第16章的增,删,改 的内容* 错误1: <insert id="addEmp" parameterType="com.bean ...

  9. bootstrap获取选中行的主键_深入分析Mybatis 使用useGeneratedKeys获取自增主键

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

最新文章

  1. deepin linux桌面设置,Deepin系统的桌面样式:高效模式和时尚模式
  2. 高内聚、低耦合的理解
  3. QT-qevent 事件的accept()和ignore()
  4. 对于DOM的attribute和property的一些思考
  5. 钱放在支付宝好,还是微信好,还是存在银行好?
  6. Centos7安装JDK8以及环境配置
  7. 南阳理工acm1043高数
  8. 看图识WAF-搜集常见WAF拦截页面
  9. 解决POI导出Excel时无法把单元格格式设置成数值类型,而不是变为货币或者自定义(附带相关问题的解决方法)
  10. 方舟手游服务器自动重启,方舟适者生存连接服务器重启怎么办_连接服务器重启解决方法_快吧单机游戏...
  11. Open3d读写ply点云文件
  12. 使用ArcGIS制作专题等值线图
  13. 字符串处理 2015百度之星资格赛 1002 列变位法解密
  14. matlab相机标定Options选项解析
  15. Windows 8 应用隐私声明——AnyRadio
  16. 网站安全狗IIS版 V4.0.15586 发布
  17. arduino新手入门详细教程系列之《Ⅰ:初识Arduino》
  18. 如何向Vive Port中上传htc vive应用
  19. Git网络通信五子棋C语言,GitHub - qq20004604/Backgammon-websocket: Backgammon五子棋网络版(websocket实现)...
  20. 10046 trace 文件内容解析

热门文章

  1. 牛客编程巅峰赛S1第6场 - 黄金钻石王者题解
  2. 5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果Matlab程序实现
  3. 经典面试题-元组和列表的区别
  4. 怎么判断噎到没噎到_宝宝噎着好了怎么判断
  5. STA切换AP过程中,STA如何识别AP,AP又反馈什么信息给STA?
  6. 使用dev-sidecar快速访问github教程
  7. 如何使用Arduino开发板和DS1307 RTC模块制作智能提醒器
  8. 【Python】爬虫面试总结分享
  9. 技术帖| 全NDI ®和NDI |HX,让技术工作更为简单的NDI协议
  10. js中for循环嵌套