在Spring中用select last_insert_id()时遇到问题(2)
来源:asp之家 发布时间:2009-05-24 19:50:00
应用层产生主键
Spring JDBC提供了自增键以及行集的支持,自增键对象让我们可以不依赖数据库的自增键,在应用层为新记录提供主键值。在JDK 1.4中引入了RowSet,它允许在连接断开的情况下操作数据,在这节里,我们将介绍如何在Spring JDBC中使用RowSet。
自增键的使用
一般数据库都提供了自增键的功能,如MySql的auto_increment、SqlServerr的identity字段等。Spring允许你在应用层产生主键值,为此定义了 org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer 接口,提供两种产生主键的方案:第一,通过序列产生主键;第二,通过表产生主键。根据主键产生方式和数据库的不同,Spring提供了若干实现类,如图 1所示:
图 1 DateFieldValueIncrementer继承类图
根据不同的主键产生方式,可能需要配置表名、主键字段名或序列名等信息。下面,我们以Oracle和MySql为例分别讲解使用序列及表字段产生主键值的方式。
DataFieldMaxValueIncrementer接口定义了3个获取下一个主键值的方法:
int nextIntValue():获取下一个主键值,主键数据类型为int;
long nextLongValue():获取下一个主键值,主键数据类型为long;
String nextStringValue():获取下一个主键值,主键数据类型为String;
在其抽象实现类AbstractDataFieldMaxValueIncrementer中,提供了几个重要的属性,其中 incrementerName定义序列或主键表的名称;如果返回的主键是String类型,则paddingLength属性可能会派上用场,它允许你指定返回主键的长度,不足的部分前面补0。
HsqlMaxValueIncrementer和MySQLMaxValueIncrementer两个主键值产生器基于表进行工作。通过 columnName属性定义主键列的名字,通过cacheSize属性定义缓存的主键个数,当内存中的主键值用完后,产生器将一次性获取 cacheSize个主键,这样可以减少数据访问的次数,提高应用的性能。
我们通过DateFieldValueIncrementer从数据库中获取主键值来弥补这个缺陷。首先,调整PostJdbcDao的代码,添加DateFieldValueIncrementer属性,并通过它从序列中得到下一个主键值:
代码清单 13 使用DateFieldValueIncrementer产生主键
public class PostJdbcDao extends JdbcDaoSupport implements PostDao { private DataFieldMaxValueIncrementer incre; ①主键值产生器 public void addPost(final Post post) { … getJdbcTemplate().execute( sql,new AbstractLobCreatingPreparedStatementCallback( this.lobHandler) { protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException { ps.setInt(1, incre.nextIntValue());②获取下一个主键值 … } }); } …//省略get/setter方法 }
在②处,我们通过incre.nextIntValue()获取下一个主键值。
以序列方式产生主键值
在Oracle数据库中创建一个seq_post_id序列,使用这个序列为t_post提供主键值,以下是创建seq_post_id的脚本:
create sequence seq_post_id increment by 1start with 1;
接着,调整Spring的配置,使用OracleSequenceMaxValueIncrementer作为主键产生器:
<bean id="incre" class="org.springframework.jdbc.support.incrementer.OracleSequenceMaxValueIncrementer"><property name="incrementerName" value="seq_post_id"/> ①指定序列名 <property name="dataSource" ref="dataSource"/> ②设置数据源 </bean><bean id="postDao" parent="dao" class="com.baobaotao.dao.jdbc.PostJdbcDao"><property name="lobHandler" ref="oracleLobHandler"/><property name="incre" ref="incre"/> ③添加主键主键产生器 </bean>
以表方式产生主键值
在Mysql中创建一张用于维护t_post主键的t_post_id表,以下是创建该表及插入初始化的SQL脚本:
create table t_post_id(sequence_id int) type = MYISAM;
insert into t_post_id values(0);
由于主键维护表的并发访问量很大,所以最好将其声明为MYISAM类型,此外需要为该表提供初始值,以便后续主键值在此之上进行递增。
调整为MySql数据库后,我们仅需要对Spring配置进行小小的调整就可以了:
<bean id="incre"class="org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer"><property name="incrementerName" value="t_post_id"/> ①设置维护主键的表名 <property name="columnName" value="sequence_id"/>②用于生成主键值的列名 <property name="cacheSize" value="10"/> ③缓存大小 <property name="dataSource" ref="dataSource"/></bean><bean id="postDao" parent="dao" class="com.baobaotao.dao.jdbc.PostJdbcDao"><property name="lobHandler" ref="defaultLobHandler"/><property name="incre" ref="incre"/></bean>
incrementerName和columnName都很容易理解,cacheSize决定一次返回的主键个数,这里我们设置为10。当第一次通过 MySQLMaxValueIncrementer# nextIntValue()获取主键值时,MySQLMaxValueIncrementer将使t_post_id. sequence_id递增10,而后续9次调用nextIntValue()方法时,都从缓存中获取主键值。直到第10次再次调用 nextIntValue()方法时,才会再次将t_post_id. sequence_id字段值递增10,如此循环反复。
小结
主键的生产方式从产生地点上可以分为应用层产生和数据库产生两种方式。应用层借助数据库的序列或表产生主键,这种方式可以保证程序的可移植性和安全性,同时可以通过缓存机制提高运行效率。有些数据库支持数据表自增键的主键产生机制,在JDBC 3.0以前的版本中,无法通过Statement自动获取新增记录的对应主键。这时需要在插入数据后,马上执行一条数据库相关的主键获取SQL语句以得到对应的主键值,在数据库高并发的情况下,有可能获取到不正确的主键值。在这种情况下,在插入数据前事先在应用层准备好主键值是很好的备选方案。
另外补充一点在SqlUpdate执行update之前需设置setReturnGeneratedKeys(true);


猜你喜欢
- 对于单页应用,官方提供了vue-router进行路由跳转的处理,本篇主要也是基于其官方文档写作而成。安装基于传统,我更喜欢采用npm包的形式
- Pandas之drop_duplicates:去除重复项方法DataFrame.drop_duplicates(subset=None, k
- 先来看一个简单的利用python调用sqlplus来输出结果的例子:import osimport sysfrom subprocess i
- Json To Dictimport jsonjsonData = '{"a":1,"b":
- 最近在工作中涉及到判断服务器所在ip反馈程序使用情况的程序主要要求就是,本机或局域网调试程序时,不反馈其域名(localhost)或ip站长
- 在网上查了部分资料但是发现粘上去的代码都存在问题,无奈只好自己修改了一下,代码如下: 如下代码能正常运行,都是网上查找资料最后拼凑总结出来的
- 为了实现挖掘,我们需要开发一个挖掘功能.挖掘功能需要在给定的消息字符串上生成摘要并提供工作证明.让我们在本章讨论这个.消息摘要函数我们将编写
- win8下python安装和环境配置,具体内容如下python语法较C语言简单,容易上手。具体步骤 1.本文采用的是win8.1 64位系统
- 一、前言Hadoop原理架构本人就不在此赘述了,可以自行百度,本文仅介绍Hadoop-3.1.2完全分布式环境搭建(本人使用三个虚拟机搭建)
- 本文实例讲述了Python实现翻转数组功能。分享给大家供大家参考,具体如下:题目描述给定一个长度为n的整数数组a,元素均不相同,问数组是否存
- sys模块 与 os包一样,也是对系统资源进行调用。功能同样也是非常丰富,接下来我们会对 sys模块的一些简单且常用的函数进行介绍,主要针对
- 中间件介绍中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与
- 1、准备工作ide:pycharmpython:3.7三方包:pygame、pyinstaller、mutagen几首mp3格式的歌2、开始
- asp之家注:也许很多人对网页设计中的,id和class和name的区别不是很清楚,好像觉得都可以使用,没什么不同。就我个人来讲,我的理解是
- 如下所示:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional
- 1. 针对问题在编程开发的过程中,我们经常会有创建同类对象的场景,这样的操作可能会对性能产生影响,一个比较常见的做法是使用对象池,需要创建对
- 用javascript实现Base64编码—解决中文问题因javascript求出来的是Unicode要转换成Ansi后才能对它进行Base
- 1、查询语句的执行顺序select[distinct] from join(如left 
- 前言去年暑假参加了一个比赛,比赛内容中需要确定目标的位置 本来想全用图像完成的,最后发现不是很符合要求。比完赛之后,就忙别的事了。直到现在突
- PYTHON3介绍Python是著名的“龟叔”Guido van Rossum在 * 圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语