2012-08-03 43 views
1

我在使用mySQL和Spring JDBCTemplate時遇到了一些麻煩。我有一個INSERT ... ON DUPLICATE KEY UPDATE,它增加了一個計數器,但是使用LAST_INSERT_ID()技巧通過最後生成的ID返回同一個查詢中的新值。我正在使用PreparedStatementCreator和GeneratedKeyHolder的JDCTemplate.update(),但我在KeyHolder.getKeyList()中獲取了多個條目。當我在mySQL客戶端手動運行它時,我得到2行受到影響(當它遇到DUPLICATE KEY UPDATE時),然後SELECT LAST_INSERT_ID();給我正確的值。由LAST_INSERT_ID()設置的JDBCTemplate檢索值問題mySQL trick

更新:它看起來像keyList中的3個條目都有1個條目,它們都是遞增值。因此,keyList.get(0).get(0)具有應該返回的值,然後keyList.get(0).get(1)是之前的值+1,然後是keyList.get(0).get (2)是以前的值+1。舉例來說,如果4是應該返回的值,它會按照這個順序給我4,5,6。

相關的代碼是:

CREATE TABLE IF NOT EXISTS `ClickChargeCheck` (
uuid VARCHAR(50), 
count INTEGER Default '0', 
CreatedOn Timestamp DEFAULT '0000-00-00 00:00:00', 
UpdatedOn Timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
PRIMARY KEY (`uuid`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

String CLICK_CHARGE_CHECK_QUERY = "INSERT INTO ClickChargeCheck (uuid,count,CreatedOn) VALUES(?,LAST_INSERT_ID(1),NOW()) ON DUPLICATE KEY UPDATE count = LAST_INSERT_ID(count+1)"; 
... 
... 
GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); 

centralStatsJdbcTemplate.update(new PreparedStatementCreator() { 
    @Override 
    public PreparedStatement createPreparedStatement(Connection con) throws SQLException { 
     PreparedStatement ps = con.prepareStatement(CLICK_CHARGE_CHECK_QUERY, Statement.RETURN_GENERATED_KEYS); 
     ps.setString(1, uuid); 
     return ps; 
    }}, keyHolder); 

int count = keyHolder.getKey().intValue(); 

回答

0

原來,MySQL的PreparedStatement的運行該查詢,並表示它返回3行。因此,getGeneratedKeys()調用(委託給StatementImpl.getGeneratedKeysInternal()),因爲它看到3行返回,所以抓取第一個LAST_INSERT_ID()值,然後從那裏遞增,直到行數。所以,我必須抓住GeneratedKeyHolder.getKeyList()並獲取第一個條目,並獲取它的第一個值,這將是我需要的值。

2

對我來說,我遇到了同樣的問題。對於INSERT ... ON DUPLICATE KEY UPDATE,GeneratedKeyHolder拋出一個異常,因爲它期望只有一個返回鍵,而MySQL不是這種情況。我基本上必須實現一個可以處理多個返回鍵的KeyHolder的新實現。

public class DuplicateKeyHolder implements KeyHolder { 
    private final List<Map<String, Object>> keyList; 

    /* Constructors */ 

    public Number getKey() throws InvalidDataAccessApiUsageException, DataRetrievalFailureException { 
     if (this.keyList.isEmpty()) { 
      return null; 
     } 
     Iterator<Object> keyIter = this.keyList.get(0).values().iterator(); 
     if (keyIter.hasNext()) { 
      Object key = keyIter.next(); 
      if (!(key instanceof Number)) { 
       throw new DataRetrievalFailureException(
         "The generated key is not of a supported numeric type. " + 
         "Unable to cast [" + (key != null ? key.getClass().getName() : null) + 
         "] to [" + Number.class.getName() + "]"); 
      } 
      return (Number) key; 
     } else { 
      throw new DataRetrievalFailureException("Unable to retrieve the generated key. " + 
        "Check that the table has an identity column enabled."); 
     } 
    } 

    public Map<String, Object> getKeys() throws InvalidDataAccessApiUsageException { 
     if (this.keyList.isEmpty()) { 
      return null; 
     } 
     return this.keyList.get(0); 
    } 

    public List<Map<String, Object>> getKeyList() { 
     return this.keyList; 
    } 
} 

如果你只是使用這個類,否則你會使用GeneratedKeyHolder,一切正常。而且我發現你甚至不需要在你的insert語句中添加... ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id) ...