2013-09-30 61 views
6

我試圖使用Spring的JdbcTemplate類將行插入名爲transaction的MySQL表中並獲取生成的ID。相關的代碼是:插入行並生成ID

public Transaction insertTransaction(final Transaction tran) { 

    // Will hold the ID of the row created by the insert 
    KeyHolder keyHolder = new GeneratedKeyHolder(); 

    getJdbcTemplate().update(new PreparedStatementCreator() { 
     public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { 

      PreparedStatement ps = connection.prepareStatement(INSERT_TRAN_SQL); 
      ps.setString(1, tran.getTransactionType().toString()); 

      Date sqlDate = new Date(tran.getDate().getTime()); 
      ps.setDate(2, sqlDate); 
      ps.setString(3, tran.getDescription()); 

      return ps; 
     } 
    }, keyHolder); 

    tran.setId(keyHolder.getKey().longValue()); 
    return tran; 
} 

但以下異常由呼叫拋向getJdbcTemplate().update

值java.sql.SQLException:沒有要求生成的密鑰。 您需要將Statement.RETURN_GENERATED_KEYS指定爲 Statement.executeUpdate()或Connection.prepareStatement()。

我可以插入行並獲取生成的ID,而不會丟棄JdbcTemplate?我使用Spring 2.5,MySQL 5.5.27和MySQL Connector 5.1.26。

+0

用MySQL,我想你會需要調用'LAST_INSERT_ID()'。參見[這裏](http://stackoverflow.com/questions/7501464/how-to-get-the-id-of-inserted-row-in-mysql)。 –

回答

7

只需準備Statement如下

PreparedStatement ps = connection.prepareStatement(
          INSERT_TRAN_SQL, Statement.RETURN_GENERATED_KEYS); 

底層的JDBC驅動程序(通過間接使用Spring的JdbcTemplate這裏)需要你想獲得生成密鑰的提示。這是可以做到無論是在準備一個PreparedStatement

connection.prepareStatement(strSQL, Statement.RETURN_GENERATED_KEYS); 

,或者在執行的時候Statement作爲

statement.executeUpdate(strSQL, Statement.RETURN_GENERATED_KEYS); 

這是你的java.sql.SQLException在和指指點點。

+1

嗨,只是一個問題,如果查詢成功,它會返回生成的ID,但如果查詢執行失敗,它會返回什麼,以便我可以在我的代碼中正常處理錯誤? –

9

還有一個更簡單的方式來獲得這種行爲:

protected JdbcTemplate   jdbcTemplate; 
private SimpleJdbcInsert   insert; 

    this.jdbcTemplate = new JdbcTemplate(this.databaseSetup.getDataSource()); 
    this.insert = new SimpleJdbcInsert(this.jdbcTemplate).withTableName(this.tableName).usingGeneratedKeyColumns(this.pkColumn); 

然後創建一個名爲參數地圖,conmtains數值爲表中的每一列的名稱和插入這樣的記錄:

final Map<String, Object> parameters = new HashMap<>(); 
    parameters.put("empName", employee.getName()); // store the String name of employee in the column empName 
    parameters.put("dept", employee.getDepartment()); // store the int (as Integer) of the employee in the column dept 
    final Number key = this.insert.executeAndReturnKey(parameters); 
    final long pk = key.longValue(); 
+0

如果您在答案中提供了映射值的示例,那將會很棒。從當前的答案來看,使用Map 並不是顯而易見的,沒有深入研究外部文檔以及Key和Value所代表的內容。 如果可以獲得這些信息,這將會得到滿意的結果。 – Hazok

+0

我認爲這很明顯,如果我提到包含每個列名的值的Map參數,就像我提到的列名一樣,它應該是顯而易見的,關鍵字是字符串,而未確定的值可以是任何映射到sql類型的對象。順便說一句:它從來沒有傷害檢查文件,永遠不會相信任何特定的答案,而不是檢查它。 – GerritCap

+0

這是顯而易見的檢查文件,而不是相信一個特定的答案。很明顯,在Stackoverflow上的一個很好的問題提供了所有必要的細節,並且不留下任何含糊的東西。 很明顯,第一個使用Java JDBC堆棧的人不會看到這些類型的東西,因爲這很明顯;) – Hazok

0

您可以檢索下一個序列號一樣在步驟1中,那麼它可以在INSERT語句通過在步驟2:

1-

Integer nextSeq = (Integer) getJdbcTemplate().queryForObject(
     "select SEQ_CUSTOMER_ID.nextVal from dual", new Object[] {}, Integer.class); 

2-

getJdbcTemplate().update(
     "INSERT INTO customer " 
     + "(CUST_ID, NAME, UPDATED) VALUES (?, ?, ?)", 
     new Object[] { nextSeq ,customer.getName(), 
       customer.getUpdated() });