欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Spring源代碼分析(三):Spring JDBC

Spring源代碼分析(三):Spring JDBC

下面我們看看Spring JDBC相關(guān)的實(shí)現,

  在Spring中,JdbcTemplate是經(jīng)常被使用的類(lèi)來(lái)幫助用戶(hù)程序操作數據庫,在JdbcTemplate為用戶(hù)程序提供了許多便利的數據庫操作方法,比如查詢(xún),更新等,而且在Spring中,有許多類(lèi)似 JdbcTemplate的模板,比如HibernateTemplate等等 - 看來(lái)這是Rod.Johnson的慣用手法,一般而言這種Template中都是通過(guò)回調函數CallBack類(lèi)的使用來(lái)完成功能的,客戶(hù)需要在回調接口中實(shí)現自己需要的定制行為,比如使用客戶(hù)想要用的SQL語(yǔ)句等。不過(guò)往往Spring通過(guò)這種回調函數的實(shí)現已經(jīng)為我們提供了許多現成的方法供客戶(hù)使用。一般來(lái)說(shuō)回調函數的用法采用匿名類(lèi)的方式來(lái)實(shí)現,比如:

  代碼

JdbcTemplate = new JdbcTemplate(datasource);  

jdbcTemplate.execute(new CallBack(){  

      public CallbackInterfacedoInAction(){  

        ......  

        //用戶(hù)定義的代碼或者說(shuō)Spring替我們實(shí)現的代碼  

      }  

} 

  在模板中嵌入的是需要客戶(hù)化的代碼,由Spring來(lái)作或者需要客戶(hù)程序親自動(dòng)手完成。下面讓我們具體看看在JdbcTemplate中的代碼是怎樣完成使命的,我們舉JdbcTemplate.execute()為例,這個(gè)方法是在JdbcTemplate中被其他方法調用的基本方法之一,客戶(hù)程序往往用這個(gè)方法來(lái)執行基本的SQL語(yǔ)句:

  代碼

public Object execute(ConnectionCallback action) throws DataAccessException {  

  //這里得到數據庫聯(lián)接  

  Connection con = DataSourceUtils.getConnection(getDataSource());  

  try {  

    Connection conToUse = con;  

    //有些特殊的數據庫,需要我們使用特別的方法取得datasource  

    if (this.nativeJdbcExtractor != null) {  

      // Extract native JDBC Connection, castable to OracleConnection or the like.  

      conToUse = this.nativeJdbcExtractor.getNativeConnection(con);  

    }  

    else {  

      // Create close-suppressing Connection proxy, also preparing returned Statements.  

      conToUse = createConnectionProxy(con);  

    }  

  //這里調用的是傳遞進(jìn)來(lái)的匿名類(lèi)的方法,也就是用戶(hù)程序需要實(shí)現CallBack接口的地方?! ?/p>

    return action.doInConnection(conToUse);  

  }  

  catch (SQLException ex) {  

    //如果捕捉到數據庫異常,把數據庫聯(lián)接釋放,同時(shí)拋出一個(gè)經(jīng)過(guò)Spring轉換過(guò)的Spring數據庫異常,  

    //我們知道,Spring做了一個(gè)有意義的工作是把這些數據庫異常統一到自己的異常體系里了?! ?/p>

    DataSourceUtils.releaseConnection(con, getDataSource());  

    con = null;  

    throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);  

  }  

  finally {  

    //最后不管怎樣都會(huì )把數據庫連接釋放  

    DataSourceUtils.releaseConnection(con, getDataSource());  

  }  

}

對于JdbcTemplate中給出的其他方法,比如query,update,execute等的實(shí)現,我們看看query():

  代碼

public Object query(PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse)  

    throws DataAccessException {  

  ..........  

  //這里調用了我們上面看到的execute()基本方法,然而這里的回調實(shí)現是Spring為我們完成的查詢(xún)過(guò)程  

  return execute(psc, new PreparedStatementCallback() {  

    public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {  

      //準備查詢(xún)結果集  

      ResultSet rs = null;  

      try {  

      //這里配置SQL參數  

        if (pss != null) {  

          pss.setValues(ps);  

        }  

     //這里執行的SQL查詢(xún)  

        rs = ps.executeQuery();  

        ResultSet rsToUse = rs;  

        if (nativeJdbcExtractor != null) {  

          rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);  

        }  

     //返回需要的記錄集合  

        return rse.extractData(rsToUse);  

      }  

      finally {  

    //最后關(guān)閉查詢(xún)的紀錄集,對數據庫連接的釋放在execute()中釋放,就像我們在上面分析的看到那樣?! ?/p>

        JdbcUtils.closeResultSet(rs);  

        if (pss instanceof ParameterDisposer) {  

          ((ParameterDisposer) pss).cleanupParameters();  

        }  

      }  

    }  

  });  

} 

輔助類(lèi)DataSourceUtils來(lái)用來(lái)對數據庫連接進(jìn)行管理的主要工具,比如打開(kāi)和關(guān)閉數據庫連接等基本操作:

  代碼

public static Connection doGetConnection(DataSource dataSource) throws SQLException {  

  //把對數據庫連接放到事務(wù)管理里面進(jìn)行管理  

  ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);  

  if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {  

    conHolder.requested();  

    if (!conHolder.hasConnection()) {  

      logger.debug("Fetching resumed JDBC Connection from DataSource");  

      conHolder.setConnection(dataSource.getConnection());  

    }  

    return conHolder.getConnection();  

  }  

  // 這里得到需要的數據庫連接,在配置文件中定義好的?! ?/p>

  logger.debug("Fetching JDBC Connection from DataSource");  

  Connection con = dataSource.getConnection();  

 

  if (TransactionSynchronizationManager.isSynchronizationActive()) {  

    logger.debug("Registering transaction synchronization for JDBC Connection");  

    // Use same Connection for further JDBC actions within the transaction.  

    // Thread-bound object will get removed by synchronization at transaction completion.  

    ConnectionHolder holderToUse = conHolder;  

    if (holderToUse == null) {  

      holderToUse = new ConnectionHolder(con);  

    }  

    else {  

      holderToUse.setConnection(con);  

    }  

    holderToUse.requested();  

    TransactionSynchronizationManager.registerSynchronization(  

        new ConnectionSynchronization(holderToUse, dataSource));  

    holderToUse.setSynchronizedWithTransaction(true);  

    if (holderToUse != conHolder) {  

      TransactionSynchronizationManager.bindResource(dataSource, holderToUse);  

    }  

  }  

 

  return con;  

}

那我們實(shí)際的DataSource對象是怎樣得到的?很清楚我們需要在上下文中進(jìn)行配置:它作為JdbcTemplate父類(lèi)JdbcAccessor的屬性存在:

  代碼

public abstract class JdbcAccessor implements InitializingBean {  

 

  /** 這里是我們依賴(lài)注入數據庫數據源的地方。 */ 

  private DataSource dataSource;  

 

  /** Helper to translate SQL exceptions to DataAccessExceptions */ 

  private SQLExceptionTranslator exceptionTranslator;  

 

  private boolean lazyInit = true;  

 

  ........  

} 

  而對于DataSource的緩沖池實(shí)現,我們通過(guò)定義Apache Jakarta Commons DBCP或者C3P0提供的DataSource來(lái)完成,然后只要在上下文中配置好就可以使用了。從上面我們看到JdbcTemplate提供了許多簡(jiǎn)單查詢(xún)和更新功能,但是如果需要更高層次的抽象,以及更面向對象的方法來(lái)訪(fǎng)問(wèn)數據庫。Spring為我們提供了org.springframework.jdbc.object包,這里面包含了SqlQuery,SqlMappingQuery, SqlUpdate和StoredProcedure等類(lèi),這些類(lèi)都是Spring JDBC應用程序可以使用的主要類(lèi),但我們要注意使用這些類(lèi)的時(shí)候,用戶(hù)需要為他們配置好一個(gè)JdbcTemplate作為其基本的操作的實(shí)現。

  比如說(shuō)我們使用MappingSqlQuery來(lái)將表數據直接映射到一個(gè)對象集合 - 具體可以參考書(shū)中的例子

  1.我們需要建立DataSource和sql語(yǔ)句并建立持有這些對象的MappingSqlQuery對象

  2.然后我們需要定義傳遞的SqlParameter,具體的實(shí)現我們在MappingSqlQuery的父類(lèi)RdbmsOperation中可以找到:

  代碼

public void declareParameter(SqlParameter param) throws InvalidDataAccessApiUsageException {  

  //如果聲明已經(jīng)被編譯過(guò),則該聲明無(wú)效  

  if (isCompiled()) {  

    throw new InvalidDataAccessApiUsageException("Cannot add parameters once query is compiled");  

  }  

  //這里對參數值進(jìn)行聲明定義  

  this.declaredParameters.add(param); 

而這個(gè)declareParameters維護的是一個(gè)列表:

  代碼

  /** List of SqlParameter objects */ 

  private List declaredParameters = new LinkedList();  

  這個(gè)列表在以后compile的過(guò)程中會(huì )被使用。

  3.然后用戶(hù)程序需要實(shí)現MappingSqlQuery的mapRow接口,將具體的ResultSet數據生成我們需要的對象,這是我們迭代使用的方法。1,2,3步實(shí)際上為我們定義好了一個(gè)迭代的基本單元作為操作模板。

  4.在應用程序,我們直接調用execute()方法得到我們需要的對象列表,列表中的每一個(gè)對象的數據來(lái)自于執行SQL語(yǔ)句得到記錄集的每一條記錄,事實(shí)上執行的execute在父類(lèi)SqlQuery中起作用:

  代碼

public List executeByNamedParam(Map paramMap, Map context) throws DataAccessException {  

  validateNamedParameters(paramMap);  

  Object[] parameters = NamedParameterUtils.buildValueArray(getSql(), paramMap);  

  RowMapper rowMapper = newRowMapper(parameters, context);  

  String sqlToUse = NamedParameterUtils.substituteNamedParameters(getSql(), new MapSqlParameterSource(paramMap));  

  //我們又看到了JdbcTemplate,這里使用JdbcTemplate來(lái)完成對數據庫的查詢(xún)操作,所以我們說(shuō)JdbcTemplate是基本的操作類(lèi)?! ?/p>

   return getJdbcTemplate().query(newPreparedStatementCreator(sqlToUse, parameters), rowMapper);  

}

  在這里我們可以看到template模式的精彩應用和對JdbcTemplate的靈活使用。通過(guò)使用它,我們免去了手工迭代ResultSet并將其中的數據轉化為對象列表的重復過(guò)程。在這里我們只需要定義SQL語(yǔ)句和SqlParameter - 如果需要的話(huà),往往SQL語(yǔ)句就常常能夠滿(mǎn)足我們的要求了。這是靈活使用JdbcTemplate的一個(gè)很好的例子。

Spring還為其他數據庫操作提供了許多服務(wù),比如使用SqlUpdate插入和更新數據庫,使用UpdatableSqlQuery更新ResultSet,生成主鍵,調用存儲過(guò)程等。

  書(shū)中還給出了對BLOB數據和CLOB數據進(jìn)行數據庫操作的例子:

  對BLOB數據的操作通過(guò)LobHander來(lái)完成,通過(guò)調用JdbcTemplate和RDBMS都可以進(jìn)行操作:

  在JdbcTemplate中,具體的調用可以參考書(shū)中的例子 - 是通過(guò)以下調用起作用的:

  代碼

public Object execute(String sql, PreparedStatementCallback action) throws DataAccessException {  

  return execute(new SimplePreparedStatementCreator(sql), action);  

}  

  然后通過(guò)對實(shí)現PreparedStatementCallback接口的AbstractLobCreatingPreparedStatementCallback的回調函數來(lái)完成:

  代碼

public final Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {  

  LobCreator lobCreator = this.lobHandler.getLobCreator();  

  try {  

    //這是一個(gè)模板方法,具體需要由客戶(hù)程序實(shí)現  

    setValues(ps, lobCreator);  

    return new Integer(ps.executeUpdate());  

  }  

  finally {  

    lobCreator.close();  

  }  

}  

//定義的需要客戶(hù)程序實(shí)現的虛函數  

protected abstract void setValues(PreparedStatement ps, LobCreator lobCreator)  

    throws SQLException, DataAccessException;  

  而我們注意到setValues()是一個(gè)需要實(shí)現的抽象方法,應用程序通過(guò)實(shí)現setValues來(lái)定義自己的操作 - 在setValues中調用lobCreator.setBlobAsBinaryStrem()。讓我們看看具體的BLOB操作在LobCreator是怎樣完成的,我們一般使用DefaultLobCreator作為BLOB操作的驅動(dòng):

  代碼

public void setBlobAsBinaryStream(  

    PreparedStatement ps, int paramIndex, InputStream binaryStream, int contentLength)  

    throws SQLException {  

  //通過(guò)JDBC來(lái)完成對BLOB數據的操作,對Oracle,Spring提供了OracleLobHandler來(lái)支持BLOB操作?! ?/p>

  ps.setBinaryStream(paramIndex, binaryStream, contentLength);  

  ........  

} 

  上面提到的是零零碎碎的Spring JDBC使用的例子,可以看到使用Spring JDBC可以幫助我們完成許多數據庫的操作。Spring對數據庫操作最基本的服務(wù)是通過(guò)JdbcTeamplate和他常用的回調函數來(lái)實(shí)現的,在此之上,又提供了許多RMDB的操作來(lái)幫助我們更便利的對數據庫的數據進(jìn)行操作 - 注意這里沒(méi)有引入向Hibernate這樣的O/R方案。對這些O/R方案的支持,Spring由其他包來(lái)完成服務(wù)。

  書(shū)中還提到關(guān)于execute和update方法之間的區別,update方法返回的是受影響的記錄數目的一個(gè)計數,并且如果傳入參數的話(huà),使用的是java.sql.PreparedStatement,而execute方法總是使用 java.sql.Statement,不接受參數,而且他不返回受影響記錄的計數,更適合于創(chuàng )建和丟棄表的語(yǔ)句,而update方法更適合于插入,更新和刪除操作,這也是我們在使用時(shí)需要注意的。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
深入解析Java的Spring框架中的混合事務(wù)與bean的區分
使用spring的動(dòng)態(tài)路由實(shí)現數據庫讀寫(xiě)分離【數據庫讀寫(xiě)分離(二) 】
10年開(kāi)發(fā)經(jīng)驗程序員一文帶你把5種數據庫操作框架給直接理解透徹
spring事務(wù)管理器設計思想(一)
Spring里使用JDBC
Spring的JNDI數據源連接池配置示例及Spring對JNDI實(shí)現分析
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久