Spring JDBC的设计与实现

设计原理

在Spring JDBC中,JdbcTemplate 是一个主要的模板类,它的类继承关系如图:

从类继承关系上来看,JdbcTemplate继承了基类JdbcAccessor和接口类JdbcOperation。在基类JdbcAccessor的设计中,对DataSource数据源进行管理和配里。在JdbcOperation接口中,定义了通过JDBC操作数据库的墓本操作方法。而JdbcTemplate提供这些接口方法的实现,比如execute方法、query方法、update方法等。

看JdbcTemplate主要是看excute()方法和query()等方法的实现,下面来来一个一个的分析。

JdbcTemplate的execute实现

    //这是使用java.sgl.Statement处理静态sql语句的方法
    public <T> T execute(StatementCallback<T> action) throws DataAccessException {
        Assert.notNull(action, "Callback object must not be null");

        //这里取得数据库的Connection,这个数据库的Connection已经在Spring的事务管理之下
        Connection con = DataSourceUtils.getConnection(this.getDataSource());
        Statement stmt = null;

        Object var7;
        try {
            Connection conToUse = con;
            if (this.nativeJdbcExtractor != null && this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
                conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
            }

            //创建Statement 语句
            stmt = conToUse.createStatement();
            this.applyStatementSettings(stmt);
            Statement stmtToUse = stmt;
            if (this.nativeJdbcExtractor != null) {
                stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
            }
            //这里调用回调函数
            T result = action.doInStatement(stmtToUse);
            this.handleWarnings(stmt);
            var7 = result;
        } catch (SQLException var11) {
            //如果捕捉到数据库异常.把数据库Connection释放。同时抛出一个经过Spring转换过的Spring数据库异常
            JdbcUtils.closeStatement(stmt);
            stmt = null;
            DataSourceUtils.releaseConnection(con, this.getDataSource());
            con = null;
            throw this.getExceptionTranslator().translate("StatementCallback", getSql(action), var11);
        } finally {
            JdbcUtils.closeStatement(stmt);
            //释放数据库Connection 
            DataSourceUtils.releaseConnection(con, this.getDataSource());
        }

        return var7;
    }

    //execute方法执行的是输入的SQL语旬,使用的方法类
    public void execute(final String sql) throws DataAccessException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Executing SQL statement [" + sql + "]");
        }

        class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider {
            ExecuteStatementCallback() {
            }

            public Object doInStatement(Statement stmt) throws SQLException {
                stmt.execute(sql);
                return null;
            }

            public String getSql() {
                return sql;
            }
        }

        this.execute((StatementCallback)(new ExecuteStatementCallback()));
    }

execute的实现中看到了对数据库进行操作的基木过程,比如需要取得数据库Connection,根据应用对数据库操作的需要创建数据库的Statement,对数据库操作进行回调,处理数据库异常,最后把数据库Connection关闭等。execute方法的设
计时序图如下:

JdbcTemplate的query实现

JdbcTemplate中给出的query, update等常用方法的实现,大多都是依抽于前面提到的execute方法,query的设计时序如下图:

源码如下:

   public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
        Assert.notNull(sql, "SQL must not be null");
        Assert.notNull(rse, "ResultSetExtractor must not be null");
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Executing SQL query [" + sql + "]");
        }

        class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
            QueryStatementCallback() {
            }

            public T doInStatement(Statement stmt) throws SQLException {
                //准备结果集
                ResultSet rs = null;

                Object var4;
                try {
                    //执行Sql查询
                    rs = stmt.executeQuery(sql);
                    ResultSet rsToUse = rs;
                    if (JdbcTemplate.this.nativeJdbcExtractor != null) {
                        rsToUse = JdbcTemplate.this.nativeJdbcExtractor.getNativeResultSet(rs);
                    }
                    //返回需要的结果集记录
                    var4 = rse.extractData(rsToUse);
                } finally {
                    //关闭操作
                    JdbcUtils.closeResultSet(rs);
                }

                return var4;
            }

            public String getSql() {
                return sql;
            }
        }

        return this.execute((StatementCallback)(new QueryStatementCallback()));
    }

    public void query(String sql, RowCallbackHandler rch) throws DataAccessException {
        this.query((String)sql, (ResultSetExtractor)(new JdbcTemplate.RowCallbackHandlerResultSetExtractor(rch)));
    }

使用数据库Connection

在以上这些对数据库的操作中,使用了辅助类DataSourceUtils,Spring通过这个辅助类来对数据的Connection进行管理。比如利用它来完成打开和关闭Connection等。DataSourceUtils对这些数据库Connection管理的实现。在数据库应用中,数据库Connection的使用往往与事务管理有很紧密的联系,这里也可以看到与事务处理相关的操作,比如Connection和当前线程的绑定等。源码如下:

    //这是取得连接的调用.是通过调用doGetConnection完成的,这里执行了异常的转换操作
    public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
        try {
            return doGetConnection(dataSource);
        } catch (SQLException var2) {
            throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", var2);
        }
    }

    public static Connection doGetConnection(DataSource dataSource) throws SQLException {
        Assert.notNull(dataSource, "No DataSource specified");
        //把对数据库的Connection放到事务管理中进行管理.这里使用在TransactionSynchronizationManager中
        //的ThreadLocal来实现线程绑定数据库连接
        ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);
        if (conHolder == null || !conHolder.hasConnection() && !conHolder.isSynchronizedWithTransaction()) {
            logger.debug("Fetching JDBC Connection from DataSource");
            //这里得到有要的数据库Connection,它是在Bean配置文件中定义好的
            Connection con = dataSource.getConnection();
            if (TransactionSynchronizationManager.isSynchronizationActive()) {
                logger.debug("Registering transaction synchronization for JDBC Connection");
                ConnectionHolder holderToUse = conHolder;
                if (conHolder == null) {
                    holderToUse = new ConnectionHolder(con);
                } else {
                    conHolder.setConnection(con);
                }

                holderToUse.requested();
                //数据库连接和线程绑定操作通过TransactionSynchronizationManager来完成
                TransactionSynchronizationManager.registerSynchronization(new DataSourceUtils.ConnectionSynchronization(holderToUse, dataSource));
                holderToUse.setSynchronizedWithTransaction(true);
                if (holderToUse != conHolder) {
                    TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
                }
            }

            return con;
        } else {
            conHolder.requested();
            if (!conHolder.hasConnection()) {
                logger.debug("Fetching resumed JDBC Connection from DataSource");
                conHolder.setConnection(dataSource.getConnection());
            }

            return conHolder.getConnection();
        }
    }

猜你喜欢

转载自blog.csdn.net/she_lock/article/details/80390158