`
fancyboy2050
  • 浏览: 240952 次
  • 性别: Icon_minigender_1
  • 来自: 皇城根儿下
社区版块
存档分类
最新评论

关于spring jdbcTemplate取得LAST_INSERT_ID

 
阅读更多
spring的jdbctemplate提供的方案:
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);
    }
分享到:
评论

相关推荐

    SpringJDBC.rar_SpringJDBC_jdbctemplate_jdbctemplate spring

    Spring JDBC通过提供JdbcTemplate和SimpleJdbcTemplate等工具类,帮助开发者以更安全、更易于管理的方式与数据库进行交互,降低了传统JDBC代码的复杂性。下面我们将详细探讨Spring JDBC的核心概念、工作原理以及如何...

    基于注解的Spring JdbcTemplate

    &lt;bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"&gt; ``` 其中,`dataSource`是指向数据库连接池的bean,如`Apache Commons DBCP`或`HikariCP`。 ### 4. 创建数据库访问层(DAO)...

    spring-jdbcTemplate实例工程

    1. **JdbcTemplate对象**:这是Spring JdbcTemplate的核心,它包含了执行SQL语句的所有方法,如update()用于更新,query()用于查询,insert()用于插入等。 2. **参数绑定**:JdbcTemplate支持多种方式的参数绑定,...

    java-web-project.zip_jdbctemplate_js项目_spring jdbctemplate

    标题中的"java-web-project.zip_jdbctemplate_js项目_spring jdbctemplate"表明这是一个Java Web项目,使用了Spring框架的JdbcTemplate模块,并且前端部分使用了JavaScript和Ajax技术。这个项目可能是为了演示如何在...

    Spring JdbcTemplate

    以上就是关于Spring JdbcTemplate的基本介绍及其在实际项目中的应用。由于这个库主要是针对Oracle数据库设计的,所以很多特定的方法可能只适用于Oracle,比如处理lob类型数据、序列或者触发器相关的操作。在使用时,...

    SpringJdbcTemplate封装工具类

    SpringJdbcTemplate是Spring框架中用于简化Java数据库访问的工具,它是Spring JDBC模块的核心。这个封装工具类的出现是为了提供一种更简洁、易于使用的接口来执行SQL操作,减轻开发者处理数据库连接、事务管理以及...

    Spring JdbcTemplate调用Oracle存储过程实现CRUD

    使用 Spring JdbcTemplate 调用 Oracle 存储过程实现 CRUD 在本文中,我们将讨论如何使用 Spring JdbcTemplate 调用 Oracle 存储过程来实现 CRUD(Create、Read、Update、Delete)操作。我们将首先编写 Oracle 存储...

    QQQ_(S+S+H)(Spring_JdbcTemplate_dao)_方式总结

    SSH整合JdbcTemplate_dao)_方式_总结

    Spring JDBCTemplate连接池jar包

    3. `spring-jdbc-5.0.0.RELEASE.jar`:包含Spring对JDBC的支持,包括JDBCTemplate和DataSourceTransactionManager,它们是与数据库交互和管理事务的关键。 4. `spring-tx-5.0.0.RELEASE.jar`:提供了事务管理功能,...

    使用Spring JDBCTemplate进行增删改查curd操作

    在Spring框架中,JdbcTemplate是用于简化数据库操作的重要工具,它是Spring JDBC模块的一部分。通过使用JdbcTemplate,开发者可以避免编写大量的重复代码,如手动管理连接、处理结果集等,从而专注于业务逻辑。本文...

    Spring JdbcTemplate 常用方法整理

    Spring的JdbcTemplate是Spring框架中用于简化数据库操作的工具类,它是基于JDBC但又抽象出了一层,避免了直接与数据库驱动API交互,从而提高了代码的可读性和可维护性。本文将深入探讨Spring JdbcTemplate的常用方法...

    Druid数据库连接池的SpringJDBCTemplate所需的jar包

    Druid数据库连接池的SpringJDBCTemplate所需的jar包,Druid数据库连接池的SpringJDBCTemplate所需的jar包,Druid数据库连接池的SpringJDBCTemplate所需的jar包,Druid数据库连接池的SpringJDBCTemplate所需的jar包,...

    strut2+spring+springjdbctemplate做的简易登录系统

    Struts2、Spring和Spring JDBC Template是Java Web开发中常用的三个框架,它们分别负责不同的职责。Struts2作为MVC(Model-View-Controller)框架,主要处理前端请求和业务逻辑;Spring则是一个全面的后端框架,提供...

    Spring JdbcTemplate例子

    Spring JdbcTemplate是Spring框架中的一个核心组件,主要用来简化数据库操作。它提供了一种模板方法设计模式,将SQL语句的执行与结果处理进行了抽象,使得开发者可以更加专注于业务逻辑,而无需关心底层数据访问的...

    Spring JdbcTemplate查询实例

    Spring JdbcTemplate是Spring框架中用于简化数据库操作的一个重要组件,它是Spring对JDBC的轻量级封装,旨在提供一种结构良好、易于使用的SQL执行机制,同时保持了JDBC的灵活性。在本实例中,我们将深入探讨Spring ...

    模仿spring jdbcTemplate的实现

    模仿spring jdbcTemplate的粗略实现,只有很小的参考价值,如果是java初学者可以使用这个封装好的工具进行数据库操作,只需要在db.properties里配置好driver,url等信息

    spring的jdbcTemplate小案例

    &lt;bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"&gt; ``` 或者使用Java配置: ```java @Configuration public class AppConfig { @Bean public DataSource dataSource() { ...

    Spring JdbcTemplate.batchUpdate 例子

    在Spring框架中,`JdbcTemplate`是用于简化Java数据库连接(JDBC)操作的一个核心组件。这个类提供了很多方法来执行SQL查询、更新语句,包括批处理操作。本篇文章将详细探讨`batchUpdate`方法及其在实际开发中的应用...

Global site tag (gtag.js) - Google Analytics