<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    The important thing in life is to have a great aim , and the determination

    常用鏈接

    統(tǒng)計(jì)

    IT技術(shù)鏈接

    保險(xiǎn)相關(guān)

    友情鏈接

    基金知識(shí)

    生活相關(guān)

    最新評(píng)論

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

    下面我們看看Spring JDBC相關(guān)的實(shí)現(xiàn),
    在Spring中,JdbcTemplate是經(jīng)常被使用的類來幫助用戶程序操作數(shù)據(jù)庫(kù),在JdbcTemplate為用戶程序提供了許多便利的數(shù)據(jù)庫(kù)操作方法,比如查詢,更新等,而且在Spring中,有許多類似 JdbcTemplate的模板,比如HibernateTemplate等等 - 看來這是Rod.Johnson的慣用手法,一般而言這種Template中都是通過回調(diào)函數(shù)CallBack類的使用來完成功能的,客戶需要在回調(diào)接口中實(shí)現(xiàn)自己需要的定制行為,比如使用客戶想要用的SQL語句等。不過往往Spring通過這種回調(diào)函數(shù)的實(shí)現(xiàn)已經(jīng)為我們提供了許多現(xiàn)成的方法供客戶使用。一般來說回調(diào)函數(shù)的用法采用匿名類的方式來實(shí)現(xiàn),比如:
    Java代碼 復(fù)制代碼 收藏代碼
    1. JdbcTemplate = new JdbcTemplate(datasource);   
    2. jdbcTemplate.execute(new CallBack(){   
    3.             public CallbackInterfacedoInAction(){   
    4.                ......   
    5.                //用戶定義的代碼或者說Spring替我們實(shí)現(xiàn)的代碼   
    6.             }   
    7. }  

    在模板中嵌入的是需要客戶化的代碼,由Spring來作或者需要客戶程序親自動(dòng)手完成。下面讓我們具體看看在JdbcTemplate中的代碼是怎樣完成使命的,我們舉JdbcTemplate.execute()為例,這個(gè)方法是在JdbcTemplate中被其他方法調(diào)用的基本方法之一,客戶程序往往用這個(gè)方法來執(zhí)行基本的SQL語句:
    Java代碼 復(fù)制代碼 收藏代碼
    1. public Object execute(ConnectionCallback action) throws DataAccessException {   
    2.     //這里得到數(shù)據(jù)庫(kù)聯(lián)接   
    3.     Connection con = DataSourceUtils.getConnection(getDataSource());   
    4.     try {   
    5.         Connection conToUse = con;   
    6.         //有些特殊的數(shù)據(jù)庫(kù),需要我們使用特別的方法取得datasource   
    7.         if (this.nativeJdbcExtractor != null) {   
    8.             // Extract native JDBC Connection, castable to OracleConnection or the like.   
    9.             conToUse = this.nativeJdbcExtractor.getNativeConnection(con);   
    10.         }   
    11.         else {   
    12.             // Create close-suppressing Connection proxy, also preparing returned Statements.   
    13.             conToUse = createConnectionProxy(con);   
    14.         }   
    15.     //這里調(diào)用的是傳遞進(jìn)來的匿名類的方法,也就是用戶程序需要實(shí)現(xiàn)CallBack接口的地方。   
    16.         return action.doInConnection(conToUse);   
    17.     }   
    18.     catch (SQLException ex) {   
    19.         //如果捕捉到數(shù)據(jù)庫(kù)異常,把數(shù)據(jù)庫(kù)聯(lián)接釋放,同時(shí)拋出一個(gè)經(jīng)過Spring轉(zhuǎn)換過的Spring數(shù)據(jù)庫(kù)異常,   
    20.         //我們知道,Spring做了一個(gè)有意義的工作是把這些數(shù)據(jù)庫(kù)異常統(tǒng)一到自己的異常體系里了。   
    21.         DataSourceUtils.releaseConnection(con, getDataSource());   
    22.         con = null;   
    23.         throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);   
    24.     }   
    25.     finally {   
    26.         //最后不管怎樣都會(huì)把數(shù)據(jù)庫(kù)連接釋放   
    27.         DataSourceUtils.releaseConnection(con, getDataSource());   
    28.     }   
    29. }  

    對(duì)于JdbcTemplate中給出的其他方法,比如query,update,execute等的實(shí)現(xiàn),我們看看query():
    Java代碼 復(fù)制代碼 收藏代碼
    1. public Object query(PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse)   
    2.         throws DataAccessException {   
    3.     ..........   
    4.     //這里調(diào)用了我們上面看到的execute()基本方法,然而這里的回調(diào)實(shí)現(xiàn)是Spring為我們完成的查詢過程   
    5.     return execute(psc, new PreparedStatementCallback() {   
    6.         public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {   
    7.             //準(zhǔn)備查詢結(jié)果集   
    8.             ResultSet rs = null;   
    9.             try {   
    10.             //這里配置SQL參數(shù)   
    11.                 if (pss != null) {   
    12.                     pss.setValues(ps);   
    13.                 }   
    14.           //這里執(zhí)行的SQL查詢   
    15.                 rs = ps.executeQuery();   
    16.                 ResultSet rsToUse = rs;   
    17.                 if (nativeJdbcExtractor != null) {   
    18.                     rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);   
    19.                 }   
    20.          //返回需要的記錄集合   
    21.                 return rse.extractData(rsToUse);   
    22.             }   
    23.             finally {   
    24.         //最后關(guān)閉查詢的紀(jì)錄集,對(duì)數(shù)據(jù)庫(kù)連接的釋放在execute()中釋放,就像我們?cè)谏厦娣治龅目吹侥菢印?  
    25.                 JdbcUtils.closeResultSet(rs);   
    26.                 if (pss instanceof ParameterDisposer) {   
    27.                     ((ParameterDisposer) pss).cleanupParameters();   
    28.                 }   
    29.             }   
    30.         }   
    31.     });   
    32. }  

    輔助類DataSourceUtils來用來對(duì)數(shù)據(jù)庫(kù)連接進(jìn)行管理的主要工具,比如打開和關(guān)閉數(shù)據(jù)庫(kù)連接等基本操作:
    Java代碼 復(fù)制代碼 收藏代碼
    1. public static Connection doGetConnection(DataSource dataSource) throws SQLException {   
    2.    //把對(duì)數(shù)據(jù)庫(kù)連接放到事務(wù)管理里面進(jìn)行管理   
    3.     ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);   
    4.     if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {   
    5.         conHolder.requested();   
    6.         if (!conHolder.hasConnection()) {   
    7.             logger.debug("Fetching resumed JDBC Connection from DataSource");   
    8.             conHolder.setConnection(dataSource.getConnection());   
    9.         }   
    10.         return conHolder.getConnection();   
    11.     }   
    12.     // 這里得到需要的數(shù)據(jù)庫(kù)連接,在配置文件中定義好的。   
    13.     logger.debug("Fetching JDBC Connection from DataSource");   
    14.     Connection con = dataSource.getConnection();   
    15.   
    16.     if (TransactionSynchronizationManager.isSynchronizationActive()) {   
    17.         logger.debug("Registering transaction synchronization for JDBC Connection");   
    18.         // Use same Connection for further JDBC actions within the transaction.   
    19.         // Thread-bound object will get removed by synchronization at transaction completion.   
    20.         ConnectionHolder holderToUse = conHolder;   
    21.         if (holderToUse == null) {   
    22.             holderToUse = new ConnectionHolder(con);   
    23.         }   
    24.         else {   
    25.             holderToUse.setConnection(con);   
    26.         }   
    27.         holderToUse.requested();   
    28.         TransactionSynchronizationManager.registerSynchronization(   
    29.                 new ConnectionSynchronization(holderToUse, dataSource));   
    30.         holderToUse.setSynchronizedWithTransaction(true);   
    31.         if (holderToUse != conHolder) {   
    32.             TransactionSynchronizationManager.bindResource(dataSource, holderToUse);   
    33.         }   
    34.     }   
    35.   
    36.     return con;   
    37. }  

    那我們實(shí)際的DataSource對(duì)象是怎樣得到的?很清楚我們需要在上下文中進(jìn)行配置:它作為JdbcTemplate父類JdbcAccessor的屬性存在:
    Java代碼 復(fù)制代碼 收藏代碼
    1. public abstract class JdbcAccessor implements InitializingBean {   
    2.   
    3.     /** 這里是我們依賴注入數(shù)據(jù)庫(kù)數(shù)據(jù)源的地方。 */  
    4.     private DataSource dataSource;   
    5.   
    6.     /** Helper to translate SQL exceptions to DataAccessExceptions */  
    7.     private SQLExceptionTranslator exceptionTranslator;   
    8.   
    9.     private boolean lazyInit = true;   
    10.   
    11.     ........   
    12. }  

    而對(duì)于DataSource的緩沖池實(shí)現(xiàn),我們通過定義Apache Jakarta Commons DBCP或者C3P0提供的DataSource來完成,然后只要在上下文中配置好就可以使用了。從上面我們看到JdbcTemplate提供了許多簡(jiǎn)單查詢和更新功能,但是如果需要更高層次的抽象,以及更面向?qū)ο蟮姆椒▉碓L問數(shù)據(jù)庫(kù)。Spring為我們提供了org.springframework.jdbc.object包,這里面包含了SqlQuery,SqlMappingQuery, SqlUpdate和StoredProcedure等類,這些類都是Spring JDBC應(yīng)用程序可以使用的主要類,但我們要注意使用這些類的時(shí)候,用戶需要為他們配置好一個(gè)JdbcTemplate作為其基本的操作的實(shí)現(xiàn)。
    比如說我們使用MappingSqlQuery來將表數(shù)據(jù)直接映射到一個(gè)對(duì)象集合 - 具體可以參考書中的例子
    1.我們需要建立DataSource和sql語句并建立持有這些對(duì)象的MappingSqlQuery對(duì)象
    2.然后我們需要定義傳遞的SqlParameter,具體的實(shí)現(xiàn)我們?cè)贛appingSqlQuery的父類RdbmsOperation中可以找到:
    Java代碼 復(fù)制代碼 收藏代碼
    1. public void declareParameter(SqlParameter param) throws InvalidDataAccessApiUsageException {   
    2.    //如果聲明已經(jīng)被編譯過,則該聲明無效   
    3.    if (isCompiled()) {   
    4.        throw new InvalidDataAccessApiUsageException("Cannot add parameters once query is compiled");   
    5.    }   
    6.    //這里對(duì)參數(shù)值進(jìn)行聲明定義   
    7.    this.declaredParameters.add(param);   

    而這個(gè)declareParameters維護(hù)的是一個(gè)列表:
    Java代碼 復(fù)制代碼 收藏代碼
    1. /** List of SqlParameter objects */  
    2. private List declaredParameters = new LinkedList();  

    這個(gè)列表在以后compile的過程中會(huì)被使用。
    3.然后用戶程序需要實(shí)現(xiàn)MappingSqlQuery的mapRow接口,將具體的ResultSet數(shù)據(jù)生成我們需要的對(duì)象,這是我們迭代使用的方法。1,2,3步實(shí)際上為我們定義好了一個(gè)迭代的基本單元作為操作模板。
    4.在應(yīng)用程序,我們直接調(diào)用execute()方法得到我們需要的對(duì)象列表,列表中的每一個(gè)對(duì)象的數(shù)據(jù)來自于執(zhí)行SQL語句得到記錄集的每一條記錄,事實(shí)上執(zhí)行的execute在父類SqlQuery中起作用:
    Java代碼 復(fù)制代碼 收藏代碼
    1. public List executeByNamedParam(Map paramMap, Map context) throws DataAccessException {   
    2.     validateNamedParameters(paramMap);   
    3.     Object[] parameters = NamedParameterUtils.buildValueArray(getSql(), paramMap);   
    4.     RowMapper rowMapper = newRowMapper(parameters, context);   
    5.     String sqlToUse = NamedParameterUtils.substituteNamedParameters(getSql(), new MapSqlParameterSource(paramMap));   
    6.     //我們又看到了JdbcTemplate,這里使用JdbcTemplate來完成對(duì)數(shù)據(jù)庫(kù)的查詢操作,所以我們說JdbcTemplate是基本的操作類。   
    7.      return getJdbcTemplate().query(newPreparedStatementCreator(sqlToUse, parameters), rowMapper);   
    8. }  

    在這里我們可以看到template模式的精彩應(yīng)用和對(duì)JdbcTemplate的靈活使用。通過使用它,我們免去了手工迭代ResultSet并將其中的數(shù)據(jù)轉(zhuǎn)化為對(duì)象列表的重復(fù)過程。在這里我們只需要定義SQL語句和SqlParameter - 如果需要的話,往往SQL語句就常常能夠滿足我們的要求了。這是靈活使用JdbcTemplate的一個(gè)很好的例子。
    Spring還為其他數(shù)據(jù)庫(kù)操作提供了許多服務(wù),比如使用SqlUpdate插入和更新數(shù)據(jù)庫(kù),使用UpdatableSqlQuery更新ResultSet,生成主鍵,調(diào)用存儲(chǔ)過程等。
    書中還給出了對(duì)BLOB數(shù)據(jù)和CLOB數(shù)據(jù)進(jìn)行數(shù)據(jù)庫(kù)操作的例子:
    對(duì)BLOB數(shù)據(jù)的操作通過LobHander來完成,通過調(diào)用JdbcTemplate和RDBMS都可以進(jìn)行操作:
    在JdbcTemplate中,具體的調(diào)用可以參考書中的例子 - 是通過以下調(diào)用起作用的:
    Java代碼 復(fù)制代碼 收藏代碼
    1. public Object execute(String sql, PreparedStatementCallback action) throws DataAccessException {   
    2.     return execute(new SimplePreparedStatementCreator(sql), action);   
    3. }  

    然后通過對(duì)實(shí)現(xiàn)PreparedStatementCallback接口的AbstractLobCreatingPreparedStatementCallback的回調(diào)函數(shù)來完成:
    Java代碼 復(fù)制代碼 收藏代碼
    1. public final Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {   
    2.     LobCreator lobCreator = this.lobHandler.getLobCreator();   
    3.     try {   
    4.         //這是一個(gè)模板方法,具體需要由客戶程序?qū)崿F(xiàn)   
    5.         setValues(ps, lobCreator);   
    6.         return new Integer(ps.executeUpdate());   
    7.     }   
    8.     finally {   
    9.         lobCreator.close();   
    10.     }   
    11. }   
    12. //定義的需要客戶程序?qū)崿F(xiàn)的虛函數(shù)   
    13. protected abstract void setValues(PreparedStatement ps, LobCreator lobCreator)   
    14.         throws SQLException, DataAccessException;  

    而我們注意到setValues()是一個(gè)需要實(shí)現(xiàn)的抽象方法,應(yīng)用程序通過實(shí)現(xiàn)setValues來定義自己的操作 - 在setValues中調(diào)用lobCreator.setBlobAsBinaryStrem()。讓我們看看具體的BLOB操作在LobCreator是怎樣完成的,我們一般使用DefaultLobCreator作為BLOB操作的驅(qū)動(dòng):
    Java代碼 復(fù)制代碼 收藏代碼
    1. public void setBlobAsBinaryStream(   
    2.         PreparedStatement ps, int paramIndex, InputStream binaryStream, int contentLength)   
    3.         throws SQLException {   
    4.     //通過JDBC來完成對(duì)BLOB數(shù)據(jù)的操作,對(duì)Oracle,Spring提供了OracleLobHandler來支持BLOB操作。   
    5.     ps.setBinaryStream(paramIndex, binaryStream, contentLength);   
    6.     ........   
    7. }  

    上面提到的是零零碎碎的Spring JDBC使用的例子,可以看到使用Spring JDBC可以幫助我們完成許多數(shù)據(jù)庫(kù)的操作。Spring對(duì)數(shù)據(jù)庫(kù)操作最基本的服務(wù)是通過JdbcTeamplate和他常用的回調(diào)函數(shù)來實(shí)現(xiàn)的,在此之上,又提供了許多RMDB的操作來幫助我們更便利的對(duì)數(shù)據(jù)庫(kù)的數(shù)據(jù)進(jìn)行操作 - 注意這里沒有引入向Hibernate這樣的O/R方案。對(duì)這些O/R方案的支持,Spring由其他包來完成服務(wù)。
    書中還提到關(guān)于execute和update方法之間的區(qū)別,update方法返回的是受影響的記錄數(shù)目的一個(gè)計(jì)數(shù),并且如果傳入?yún)?shù)的話,使用的是java.sql.PreparedStatement,而execute方法總是使用 java.sql.Statement,不接受參數(shù),而且他不返回受影響記錄的計(jì)數(shù),更適合于創(chuàng)建和丟棄表的語句,而update方法更適合于插入,更新和刪除操作,這也是我們?cè)谑褂脮r(shí)需要注意的。

    posted on 2011-10-26 23:37 鴻雁 閱讀(338) 評(píng)論(0)  編輯  收藏


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产猛男猛女超爽免费视频| 欧美日韩国产免费一区二区三区| 十八禁在线观看视频播放免费| 国产老女人精品免费视频| 亚洲精品一二三区| 99爱在线精品免费观看| 亚洲一区二区影视| 无码视频免费一区二三区| 亚洲一本到无码av中文字幕| 国产国产人免费视频成69大陆| 美女被免费网站在线视频免费| a级成人毛片免费视频高清| 在线免费视频一区| 女bbbbxxxx另类亚洲| 亚洲男人av香蕉爽爽爽爽| aa毛片免费全部播放完整| 亚洲成AV人片一区二区密柚| 羞羞漫画页面免费入口欢迎你 | 免费看内射乌克兰女| 无码国产精品一区二区免费 | 波多野结衣免费视频观看| 亚洲人成伊人成综合网久久| 免费在线观看的网站| 羞羞的视频在线免费观看| 国产V亚洲V天堂无码| 精品久久久久成人码免费动漫| 亚洲精品乱码久久久久久V| 性色午夜视频免费男人的天堂| 亚洲色图校园春色| 久久久久成人片免费观看蜜芽| 亚洲理论精品午夜电影| 免费看www视频| a毛片免费播放全部完整| 亚洲欧洲日本在线观看| 亚洲美日韩Av中文字幕无码久久久妻妇| 在线免费观看h片| 亚洲色成人WWW永久在线观看| 国产亚洲情侣一区二区无| 一级毛片免费视频网站| 久久精品国产亚洲AV无码娇色| 麻豆成人精品国产免费|