mysql高并发下主键自增打来的问题

这篇具有很好参考价值的文章主要介绍了mysql高并发下主键自增打来的问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在一般情况下,在新增领域对象后,都需要获取对应的主键值。使用应用层来维护主键,在一定程度上有利于程序性能的优化和应用移植性的提高。在采用数据库自增主键的方案里,如果JDBC驱动不能绑定新增记录对应的主键,就需要手工执行查询语句以获取对应的主键值,对于高并发的系统,这很容易返回错误的主键。通过带缓存的DataFieldMaxValueIncrementer,可以一次获取批量的主键值,供多次插入领域对象时使用,它的执行性能是很高的。

使用数据库的自增主键

我们经常使用数据的自增字段作为表主键,也即主键值不在应用层产生,而是在新增记录时,由数据库产生。这样,应用层在保存对象前并不知道对象主键值,而必须在保存数据后才能从数据库中返回主键值。在很多情况下,我们需要获取新对象持久化后的主键值。在Hibernate等ORM框架,新对象持久化后,Hibernate会自动将主键值绑定到对象上,给程序的开发带来了很多方便。

在JDBC 3.0规范中,当新增记录时,允许将数据库自动产生的主键值绑定到Statement或PreparedStatement中。使用Statement时,可以通过以下方法绑定主键值:

int executeUpdate(String sql,int autoGeneratedKeys)

也可以通过Connection创建绑定自增值的PreparedStatement:

PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)

当autoGeneratedKeys参数设置为Statement.RETURN_GENERATED_KEYS值时即可绑定数据库产生的主键值,设置为Statement.NO_GENERATED_KEYS时,不绑定主键值。下面的代码演示了Statement绑定并获取数据库产生的主键值的过程:

Statement stmt = conn.createStatement(); String sql = "INSERT INTO t_topic(topic_title,user_id) VALUES(‘测试主题’,’123’) "; stmt.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS); ①指定绑定表自增主键值ResultSet rs = stmt.getGeneratedKeys(); if( rs.next() ) { intkey = rs.getInt();②获取对应的表自增主键值}

Spring利用这一技术,提供了一个可以返回新增记录对应主键值的方法:

int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)

org.springframework.jdbc.support.KeyHolder是一个回调接口,Spring使用它保存新增记录对应的主键,该接口的接口方法描述如下:

Number getKey() throws InvalidDataAccessApiUsageException

当仅插入一行数据,主键不是复合键且是数字类型时,通过该方法可以直接返回新的主键值。如果是复合主键,或者有多个主键返回时,该方法抛出InvalidDataAccessApiUsageException。该方法是最常用的方法,因为一般情况下,我们一次仅插入一条数据并且主键字段类型为数字类型;

Map getKeys() throws InvalidDataAccessApiUsageException

如果是复合主键,则列名和列值构成Map中的一个Entry。如果返回的是多个主键,则该方法抛出InvalidDataAccessApiUsageException异常;

List getKeyList():

如果返回多个主键,即PreparedStatement新增了多条记录,则每一个主键对应一个Map,多个Map构成一个List。

Spring为KeyHolder接口指代了一个通用的实现类GeneratedKeyHolder,该类返回新增记录时的自增长主键值。假设我们希望在新增论坛板块对象后,希望将主键值加载到对象中,则可以按以下代码进行调整:

public voidaddForum(final Forum forum) { final String sql = “INSERT INTO t_forum(forum_name,forum_desc) VALUES(?,?)”; KeyHolder keyHolder = newGeneratedKeyHolder();①创建一个主键执有者getJdbcTemplate().update(newPreparedStatementCreator(){ public PreparedStatement createPreparedStatement(Connection conn) throws SQLException { PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, forum.getForumName()); ps.setString(2, forum.getForumDesc()); returnps; } },keyHolder); forum.setForumId(keyHolder.getKey().intValue());②从主键执有者中获取主键}

这样,在调用addForum(final Forum forum)新增forum领域对象后,forum将拥有对应的主键值,方便后继的使用。

在JDBC 3.0之前的版本中,PreparedStatement不能绑定主键,如果采用表自增键(如MySql的auto increment或SqlServer的identity)将给获取正确的主键值带来挑战——因为你必须在插入数据后,马上执行另一条获取新增主键的查询语句。表1给出了不同数据库获取最新自增主键值的查询语句:

表1 不同数据库获取新增加的主键值

数据库

获取新增主键的查询语句

DB2

IDENTITY_VAL_LOCAL()

Informix

SELECT dbinfo(‘sqlca.sqlerrd1’) FROM

Sybase

SELECT @@IDENTITY

SqlServer

SELECT SCOPE_IDENTITY()或SELECT @@IDENTITY

MySql

SELECT LAST_INSERT_ID()

HsqlDB

CALL IDENTITY()

Cloudscape

IDENTITY_VAL_LOCAL()

Derby

IDENTITY_VAL_LOCAL()

PostgreSQL

SELECT nextval(’

如果数据库的并发率很高,比如在插入记录后执行查询主键之前,数据库又执行了若干条插入记录的SQL语句,这时,通过表1 返回的主键值就是最后一条插入语句的主键值,而非我们希望的主键值了。所以使用查询语句获取表自增键值是不安全的,这也是为什么有些数据库(如Oracle、Firebird)故意不提供自增键,而只提供序列的原因,序列强制要求你在新增记录前,先获取主键值。Oracle通过SELECT .nextval FROM DUAL获取序列的下一个值,而FireBird通过SELECT GEN_ID( 1) FROM RDB$DATABASE获取序列的下一个值。在10.4.1小节中,我们还将讲解应用层自增键的相关知识。文章来源地址https://www.toymoban.com/news/detail-637704.html

到了这里,关于mysql高并发下主键自增打来的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • mybatis实战:四、insert 用法(普通插入、返回主键自增的值)

    1.UserMapper.xml 1.指定特殊数据类型 2.<insert >元素,这个标签包含如下属性  2. UserMapperTest  1.只插入一条数据 2.回滚(不写入数据库) 3.插入后判断是否为空(为空/不为空,抛异常) 3.UserMapper 方法一: 使用 JDBC 方式返回主键自增的值  方法二: 使用 selectKey 返回主键的值

    2024年02月07日
    浏览(47)
  • MySQL数据库——MySQL AUTO_INCREMENT:主键自增长

    在 MySQL 中,当主键定义为自增长后,这个主键的值就不再需要用户输入数据了,而由数据库系统根据定义自动赋值。每增加一条记录,主键会自动以相同的步长进行增长。 通过给字段添加  AUTO_INCREMENT  属性来实现主键自增长。语法格式如下: 默认情况下,AUTO_INCREMENT 的初

    2024年02月11日
    浏览(37)
  • Mysql 自增主键设置以及重置自增值

            在创建需要带自增主键的表结构时,在主键上增加AUTO_INCREMENT,同时可以设置主键的启始值AUTO_INCREMENT=1。

    2024年02月12日
    浏览(31)
  • 高并发下如何保证接口幂等

    接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题。本文分享了一些解决这类问题非常实用的办法,绝大部分内容我在项目中实践过的,给有需要的小伙伴一个参考。 不知道你有没有遇到过这些场景: 有时我们在填写某些form表单时,保存按钮不小心快速点

    2023年04月09日
    浏览(40)
  • Redis 高并发下的性能优化技术

    Redis是一款高性能的键值存储数据库。与传统的数据库相比,Redis拥有更高的读写速度以及更丰富的数据结构支持。 尽管Redis拥有出色的性能表现,但在高并发场景下其仍存在着一些性能问题需要我们注意。本文将围绕这些问题进行分析,并提供一些解决方案。 Redis采用单进程

    2024年02月10日
    浏览(53)
  • 模拟高并发下RabbitMQ的削峰作用

            在并发量很高的时候,服务端处理不过来客户端发的请求,这个时候可以使用消息队列,实现削峰。原理就是请求先打到队列上,服务端从队列里取出消息进行处理,处理不过来的消息就堆积在消息队列里等待。 可以模拟一下这个过程:         发送方把10万条

    2024年02月11日
    浏览(42)
  • mysql如何自定义自增主键值,以及所遇到的不生效问题

    最近有一个需求,要求对某些数据的数据库主键id格式化,要求id为(202311080000)的形式去自增,可以在get请求获取到这些数据时在请求路径上看到格式化的id,但是之前数据id有大于202311080000数值的,导致自增的主键值并没有生效(即使删除相关数据) 如何自定义自增主键值 第一种通过命

    2024年04月15日
    浏览(39)
  • 高并发下的缓存击穿、雪崩、穿透和分布式锁(三)

    概念: 去查询缓存和数据库都不存在的数据,然后大量请求不存在的数据,导致数据库压力过大崩溃。 解决方案: 把不存在的数据null存入缓存,并给个短期的过期时间。 概念: 缓存采用相同的过期时间,然后在某一时刻会同时过期,然后请求全部访问数据库,导致数据库

    2024年02月07日
    浏览(37)
  • 高并发下数据幂等问题的9种解决方案

    严格来说,所谓人云亦云的接口幂等性,大部分场景是要求接口防重或数据幂等,而不是接口幂等,很多人都搞混了。 举例:后端做了支付防重,用户对单一订单重复支付,再次支付不是提示支付成功(接口幂等是要求多次请求返回的结果一致),而是提示请勿重复支付。

    2024年03月23日
    浏览(36)
  • 面试官:MySQL 自增主键一定是连续的吗?大部分人都会答错!

    MySQL版本:8.0 数据库表:T (主键id,唯一索引c,普通字段d) 如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不能保证连续递增。 推荐一个开源免费的 Spring Boot 实战项目: https://github.com/javastacks

    2024年02月06日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包