spring的jdbctemplate提供的方案:mysql
KeyHolder keyHolder = new GeneratedKeyHolder(); int updatecount = jdbcTemplate.update(new PreparedStatementCreator() { @Override public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { PreparedStatement ps = (PreparedStatement) connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); return ps; } }, keyHolder); long id = keyHolder.getKey().longValue();
jdbctemplate中執行的相關源碼spring
public int update(PreparedStatementCreator psc, final KeyHolder generatedKeyHolder) throws DataAccessException { Assert.notNull(generatedKeyHolder, "KeyHolder must not be null"); logger.debug("Executing SQL update and returning generated keys"); Integer result = (Integer)execute(psc, new PreparedStatementCallback() { public Object doInPreparedStatement(PreparedStatement ps) throws SQLException { //第一步:經過PreparedStatement對象先執行相關sql int rows = ps.executeUpdate(); List generatedKeys = generatedKeyHolder.getKeyList(); generatedKeys.clear(); //第二步:經過同一個PreparedStatement取得產生的auto-generated keys ResultSet keys = ps.getGeneratedKeys(); if(keys != null) try { RowMapper rowMapper = getColumnMapRowMapper(); RowMapperResultSetExtractor rse = new RowMapperResultSetExtractor(rowMapper, 1); //解析取得的ResultSet,放入到holder對象的,供咱們的應用程序使用 generatedKeys.addAll((List)rse.extractData(keys)); } finally { JdbcUtils.closeResultSet(keys); } if(JdbcTemplate.this.this$0.isDebugEnabled()) JdbcTemplate.this.this$0.debug("SQL update affected " + rows + " rows and returned " + generatedKeys.size() + " keys"); return new Integer(rows); } { super(); } } ); return result.intValue(); }
查看相關PreparedStatement對象的具體執行源碼sql
public int executeUpdate() throws SQLException { return executeUpdate(true, false); } protected int executeUpdate(boolean clearBatchedGeneratedKeysAndWarnings, boolean isBatch) throws SQLException { if(clearBatchedGeneratedKeysAndWarnings) { clearWarnings(); batchedGeneratedKeys = null; } return executeUpdate(parameterValues, parameterStreams, isStream, streamLengths, isNull, isBatch); } protected int executeUpdate(byte batchedParameterStrings[][], InputStream batchedParameterStreams[], boolean batchedIsStream[], int batchedStreamLengths[], boolean batchedIsNull[], boolean isReallyBatch) throws SQLException { checkClosed(); //這個connection就是咱們具體使用的鏈接的對象,具體實現就是jdbc的connection對象 Connection locallyScopedConn = connection; if(locallyScopedConn.isReadOnly()) throw SQLError.createSQLException(Messages.getString("PreparedStatement.34") + Messages.getString("PreparedStatement.35"), "S1009"); if(firstCharOfStmt == 'S' && StringUtils.startsWithIgnoreCaseAndWs(originalSql, "SELECT")) throw SQLError.createSQLException(Messages.getString("PreparedStatement.37"), "01S03"); if(results != null && !locallyScopedConn.getHoldResultsOpenOverStatementClose()) results.realClose(false); com.mysql.jdbc.ResultSet rs = null; synchronized(locallyScopedConn.getMutex()) { Buffer sendPacket = fillSendPacket(batchedParameterStrings, batchedParameterStreams, batchedIsStream, batchedStreamLengths); String oldCatalog = null; if(!locallyScopedConn.getCatalog().equals(currentCatalog)) { oldCatalog = locallyScopedConn.getCatalog(); locallyScopedConn.setCatalog(currentCatalog); } if(locallyScopedConn.useMaxRows()) locallyScopedConn.execSQL(this, "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, null, 1003, 1007, false, currentCatalog, true); boolean oldInfoMsgState = false; if(retrieveGeneratedKeys) { oldInfoMsgState = locallyScopedConn.isReadInfoMsgEnabled(); locallyScopedConn.setReadInfoMsgEnabled(true); } //內部方法,執行獲得ResultSet對象,executeInternal方法調用傳入的connection對象的execSQL方法完成數據庫操做並獲得返回的ResultSet對象 rs = executeInternal(-1, sendPacket, false, false, true, null, isReallyBatch); if(retrieveGeneratedKeys) { locallyScopedConn.setReadInfoMsgEnabled(oldInfoMsgState); rs.setFirstCharOfQuery(firstCharOfStmt); } if(oldCatalog != null) locallyScopedConn.setCatalog(oldCatalog); } results = rs; updateCount = rs.getUpdateCount(); int truncatedUpdateCount = 0; if(updateCount > 2147483647L) truncatedUpdateCount = 2147483647; else truncatedUpdateCount = (int)updateCount; lastInsertId = rs.getUpdateID(); return truncatedUpdateCount; }
查看jdbc的Connection源碼數據庫
com.mysql.jdbc.ResultSet execSQL(com.mysql.jdbc.Statement callingStatement, String sql, int maxRows, Buffer packet, int resultSetType, int resultSetConcurrency, boolean streamResults, String catalog, boolean unpackFields, boolean isBatch) throws SQLException{ ... //關鍵執行語句,this.io是一個jdbc的mysqlio對象 return this.io.sqlQueryDirect(callingStatement, null, null, packet, maxRows, this, resultSetType, resultSetConcurrency, streamResults, catalog, unpackFields);
通過MysqlIo對象的處理,最後封裝一個包含updateCount和updateID兩個主要數據的ResultSet對象app
private com.mysql.jdbc.ResultSet buildResultSetWithUpdates( Statement callingStatement, Buffer resultPacket) throws SQLException { long updateCount = -1; long updateID = -1; String info = null; try { if (this.useNewUpdateCounts) { updateCount = resultPacket.newReadLength(); updateID = resultPacket.newReadLength(); } else { updateCount = resultPacket.readLength(); updateID = resultPacket.readLength(); } if (this.use41Extensions) { this.serverStatus = resultPacket.readInt(); this.warningCount = resultPacket.readInt(); if (this.warningCount > 0) { this.hadWarnings = true; // this is a 'latch', it's reset by sendCommand() } resultPacket.readByte(); // advance pointer if (this.profileSql) { this.queryNoIndexUsed = (this.serverStatus & SERVER_QUERY_NO_GOOD_INDEX_USED) != 0; this.queryBadIndexUsed = (this.serverStatus & SERVER_QUERY_NO_INDEX_USED) != 0; } } if (this.connection.isReadInfoMsgEnabled()) { info = resultPacket.readString(); } } catch (Exception ex) { throw SQLError.createSQLException(SQLError.get( SQLError.SQL_STATE_GENERAL_ERROR) + ": " //$NON-NLS-1$ +ex.getClass().getName(), SQLError.SQL_STATE_GENERAL_ERROR, -1); } ResultSet updateRs = new com.mysql.jdbc.ResultSet(updateCount, updateID, this.connection, callingStatement); if (info != null) { updateRs.setServerInfo(info); } return updateRs; }
回到PreparedStatement對象的executeUpdate方法ide
//把語句執行獲得的結果集交給當前對象 this.results = rs; //更新條數 this.updateCount = rs.getUpdateCount(); int truncatedUpdateCount = 0; if (this.updateCount > Integer.MAX_VALUE) { truncatedUpdateCount = Integer.MAX_VALUE; } else { truncatedUpdateCount = (int) this.updateCount; } //LAST_INSERT_ID值 this.lastInsertId = rs.getUpdateID(); return truncatedUpdateCount;
再回到jdbctemplate源碼的update方法,第一步:經過PreparedStatement對象先執行相關sql 【這部分執行已經完成,獲得的ResultSet對象值已經交給ps對象】
而後經過ps對象ps.getGeneratedKeys()得到generateKeys的值,具體處理在PreparedStatement父類Statement對象中ui
public ResultSet getGeneratedKeys() throws SQLException { if(batchedGeneratedKeys == null) { return getGeneratedKeysInternal(); } else { Field fields[] = new Field[1]; fields[0] = new Field("", "GENERATED_KEY", -5, 17); fields[0].setConnection(connection); return new com.mysql.jdbc.ResultSet(currentCatalog, fields, new RowDataStatic(batchedGeneratedKeys), connection, this); } } protected ResultSet getGeneratedKeysInternal() throws SQLException { Field fields[] = new Field[1]; fields[0] = new Field("", "GENERATED_KEY", -5, 17); fields[0].setConnection(connection); ArrayList rowSet = new ArrayList(); long beginAt = getLastInsertID(); int numKeys = getUpdateCount(); if(results != null) { String serverInfo = results.getServerInfo(); if(numKeys > 0 && results.getFirstCharOfQuery() == 'R' && serverInfo != null && serverInfo.length() > 0) numKeys = getRecordCountFromInfo(serverInfo); if(beginAt > 0L && numKeys > 0) { //根據更新條數會累加LastInsertID的值,由於在插入多條的時候只會默認返回第一條執行後產生的ID for(int i = 0; i < numKeys; i++) { byte row[][] = new byte[1][]; row[0] = Long.toString(beginAt++).getBytes(); rowSet.add(row); } } } return new com.mysql.jdbc.ResultSet(currentCatalog, fields, new RowDataStatic(rowSet), connection, this); }