spring的jdbctemplate提供的方案:
jdbctemplate中执行的相关源码
查看相关PreparedStatement对象的具体执行源码
查看jdbc的Connection源码
经过MysqlIo对象的处理,最后封装一个包含updateCount和updateID两个主要数据的ResultSet对象
回到PreparedStatement对象的executeUpdate方法
再回到jdbctemplate源码的update方法,第一步:通过PreparedStatement对象先执行相关sql 【这部分执行已经完成,得到的ResultSet对象值已经交给ps对象】
然后通过ps对象ps.getGeneratedKeys()获得generateKeys的值,具体处理在PreparedStatement父类Statement对象中
- 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中执行的相关源码
- 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对象的具体执行源码
- 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对象
- 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方法
- //把语句执行得到的结果集交给当前对象
- 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对象中
- 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);
- }
转:http://fancyboy2050.iteye.com/blog/1455559