今天在使用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);