今天在使用MySQL时却不知如何处理,插入记录后不知怎样获得刚刚插入的id,查过文档后发现了select last_insert_id(),在插入之后执行此查询,即可获得自增id,喜出望外。
可用到自己的程序中之后却得不到想要的结果,于是就怀疑到了Spring头上,因为通过基本JDBC测试是没有任何问题的,所以就去跟踪Spring JDBC, 看过源码之后才豁然开朗,原来Spring中如此获得数据库Connection的:Connection
发现了如下文章,来自IT168,标题为《Spring应用数据主键的生成策略盘点》,摘录如下:
使用数据库的自增主键
int executeUpdate(String sql,int autoGeneratedKeys)
也可以通过Connection创建绑定自增值的PreparedStatement:
PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
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() ) { int key = rs.getInt();②获取对应的表自增主键值 }
Spring利用这一技术,提供了一个可以返回新增记录对应主键值的方法:
int update(PreparedStatementCreator
org.springframework.jdbc.support.KeyHolder是一个回调接口,Spring使用它保存新增记录对应的主键,该接口的接口方法描述如下:
当 仅插入一行数据,主键不是复合键且是数字类型时,通过该方法可以直接返回新的主键值。如果是复合主键,或者有多个主键返回时,该方法抛出 InvalidDataAccessApiUsag
如果是复合主键,则列名和列值构成Map中的一个Entry。如果返回的是多个主键,则该方法抛出InvalidDataAccessApiUsag
如果返回多个主键,即PreparedStatement新增了多条记录,则每一个主键对应一个Map,多个Map构成一个List。
public void addForum(final Forum forum) { final String sql = "INSERT INTO t_forum(forum_name,forum_desc) VALUES(?,?)"; KeyHolder keyHolder = new GeneratedKeyHolder();①创建一个主键执有者 getJdbcTemplate().update(new PreparedStatementCreator
在JDBC 3.0之前的版本中,PreparedStatement不能绑定主键,如果采用表自增键(如MySql的auto increment或SqlServer的identity)将给获取正确的主键值带来挑战——因为你必须在插入数据后,马上执行另一条获取新增主键的查询语句。表 1给出了不同数据库获取最新自增主键值的查询语句:
数据库 |
获取新增主键的查询语句 |
DB2 |
IDENTITY_VAL_LOCAL() |
Informix |
SELECT dbinfo('sqlca.sqlerrd1') FROM <TABLE> |
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('<TABLE>_SEQ') |
应用层产生主键
自增键的使用
DataFieldMaxValueIncreme
int nextIntValue():获取下一个主键值,主键数据类型为int;
long nextLongValue():获取下一个主键值,主键数据类型为long;
String nextStringValue():获取下一个主键值,主键数据类型为String;
public class PostJdbcDao extends JdbcDaoSupport implements PostDao { private DataFieldMaxValueIncreme
在②处,我们通过incre.nextIntValue()获取下一个主键值。
以序列方式产生主键值
create sequence seq_post_id increment by 1start with 1;
<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>
create table t_post_id(sequence_id int) type = MYISAM;
insert into t_post_id values(0);
调整为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>
小结
另外补充一点在SqlUpdate执行update之前需设置setReturnGeneratedKeys(true);