在一般情况下,在新增领域对象后,都需要获取对应的主键值。使用应用层来维护主键,在一定程度上有利于程序性能的优化和应用移植性的提高。在采用数据库自增主键的方案里,如果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中的一个Entry。如果返回的是多个主键,则抛出InvalidDataAccessApiUsageException异常;

Map getKeys() throws InvalidDataAccessApiUsageException;

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

List getKeyList():

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(Forum forum)新增forum领域对象后,forum将拥有对应的主键值,方便后继的使用。在JDBC 3.0之前的版本中,PreparedStatement不能绑定主键,如果采用表自增键(如MySQL的auto increment或SQLServer的identity)将给获取正确的主键值带来挑战——因为你必须在插入数据后,马上执行另一条获取新增主键的查询语句。下面给出了不同数据库获取最新自增主键值的查询语句:

posted on 2011-09-25 14:27 jadmin 阅读(902) 评论(0)  编辑  收藏

java 并发 主键_高并发数据库自增主键分析相关推荐

  1. libevent c++高并发网络编程_高并发编程学习(2)——线程通信详解

    前序文章 高并发编程学习(1)--并发基础 - https://www.wmyskxz.com/2019/11/26/gao-bing-fa-bian-cheng-xue-xi-1-bing-fa-j ...

  2. java高并发编程艺术_[高并发]Java高并发编程系列开山篇--线程实现

    Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...

  3. java设计高并发内存池_高并发服务器-连接池的设计

    高并发服务器-连接池的设计 高并发服务器需要有一些池的设计,如内存池,连接池,数据库连接池. 池(pool)的设计主要考虑到一些资源的频繁申请和释放,尤其是在高并发的服务器中,几万甚至几十万并发每秒, ...

  4. 数据库mysql表怎么设置外键_如何设置数据库中的外键

    展开全部 创建数据库时就是有主键的创建了主键,但是表之间的关系没有联系,要建数据库关系图只e69da5e887aa62616964757a686964616f31333365653739有主键没有外键 ...

  5. java基础多线程抢红包_高并发开发-微信抢红包实现

    - 如果上司给一个任务,让我们在实现微信抢红包这个功能,我们该怎么做? * 业务思考,实现方式千百种,不追求方法复制,只追求推导过程的思考总结 * 功能点探索 * 新建红包:在DB.cache各新增一 ...

  6. java设计模式并发_[高并发Java 七] 并发设计模式

    [高并发Java 七] 并发设计模式 [高并发Java 七] 并发设计模式 为什么80%的码农都做不了架构师?>>> 在软件工程中,设计模式(design pattern)是对软件设 ...

  7. java currenttimemillis 效率_高并发场景下System.currentTimeMillis()的性能问题的优化

    前言 System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我也不知道,不过听说在100倍左右),然而该方法又是一个常用方法,有时不得不使用,比如生 ...

  8. java架构师眼中的高并发架构

    前言 高并发经常会发生在有大活跃用户量,用户高聚集的业务场景中,如:秒杀活动,定时领取红包等. 为了让业务可以流畅的运行并且给用户一个好的交互体验,我们需要根据业务场景预估达到的并发量等因素,来设计适 ...

  9. Java生鲜电商平台-高并发核心技术订单与库存实战

    Java生鲜电商平台-高并发核心技术订单与库存实战 一. 问题 一件商品只有100个库存,现在有1000或者更多的用户来购买,每个用户计划同时购买1个到几个不等商品. 如何保证库存在高并发的场景下是安 ...

最新文章

  1. SAP零售行业解决方案初阶 3 - WB01 创建Site Master
  2. Java之HashMap源码解析1
  3. js解决iframe跨域问题
  4. jvm在创建对象时采用哪些并发安全机制
  5. C语言模拟实现标准库函数之strlen()
  6. 深入理解 Android Activity的生命周期
  7. 一次性存入多少钱就可以有资格跟银行商谈利息了?
  8. 年轻人选择创业时,最好避开门槛低的行业
  9. linux 定位 踩内存_互联网线上系统故障定位方法论
  10. [Web开发] Web程序调式的利器 - Fiddler (HTTP协议监视工具)
  11. GMapping源码分析之随手笔记
  12. python中可变参数*args传入函数时的存储方式为,Python函数可变参数(*args,**kwargs)详解...
  13. 安捷伦仪器仪表 - 程控总结
  14. matlab基波有效值,基波有效值
  15. 国考银保监会计算机类笔试,银保监会(计算机类)笔试资料(含2018-2019真题).zip...
  16. 星辰大海,不属于任何人,也属于任何人
  17. Html源代码图片解密,通过图片加密、解密文件
  18. 75寸的电视长宽各是多少厘米
  19. 渗透常用SQL注入语句大全
  20. MySQL存储过程与存储函数

热门文章

  1. 【c++ primer读书笔记】【第2章】变量和基本类型
  2. 上传文件的跨域处理(转)
  3. 防止ASP.NET按钮多次提交的办法
  4. RedisTemplate value序列化导致的问题
  5. 面试必备:synchronized的底层原理?
  6. Program type already present: android.support.design.widget.xx
  7. Netcdf 文件多属性,按照时间段导出代码示例
  8. 微信小程序报错 .wxss 无法找到
  9. html打包成app的缓存问题,webpack 独立打包与缓存处理
  10. lwip连续发数据卡死_Mysteel:12月全球铁矿石发运量稳中微增 进口矿咋走?