您的位置:首页 > 编程语言 > Java开发

关于spring jdbcTemplate取得LAST_INSERT_ID

2016-04-27 20:31 656 查看
spring的jdbctemplate提供的方案:

Java代码


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中执行的相关源码

Java代码


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对象的具体执行源码

Java代码


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源码

Java代码


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对象

Java代码


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方法

Java代码


//把语句执行得到的结果集交给当前对象

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对象中

Java代码


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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: