日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring 4 官方文档学习(十)数据访问之JDBC

發(fā)布時(shí)間:2023/12/10 javascript 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring 4 官方文档学习(十)数据访问之JDBC 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

說明:未修訂版,閱讀起來極度困難

?

1、Spring框架JDBC的介紹

?

Spring JDBC - who does what?

動(dòng)作Spring
定義連接參數(shù)?
打開連接?
指定SQL語句?
聲明參數(shù),提供參數(shù)值?
準(zhǔn)備、執(zhí)行語句?
迭代結(jié)果(如果有)?
操作每個(gè)迭代?
處理任何異常?
處理事務(wù)?
關(guān)閉連接、語句、結(jié)果集?

一句話,Spring框架負(fù)責(zé)所有的低級別細(xì)節(jié)操作。

?

1.1、選擇JDBC數(shù)據(jù)庫訪問的路徑

所有的路徑都需要兼容JDBC 2.0的驅(qū)動(dòng),部分特性可能需要JDBC 3.0 的驅(qū)動(dòng)。

JdbcTemplate 是經(jīng)典的Spring JDBC 路徑,最流行。最低級的路徑,所有其他的底層都是用一個(gè)JdbcTemplate。

NamedParameterJdbcTemplate 封裝了一個(gè)JdbcTemplate,使用帶名字的參數(shù)取代了傳統(tǒng)的JDBC 占位符(?)。該路徑,提供了更好的文檔,當(dāng)你有很多參數(shù)時(shí),更易于使用。

SimpleJdbcInsert和SimpleJdbcCall 優(yōu)化了數(shù)據(jù)庫元數(shù)據(jù),限制了必要數(shù)據(jù)的數(shù)量。該路徑簡化了編碼,你只要提供表名或procedure并提供參數(shù)和列匹配的映射即可。這只有在數(shù)據(jù)庫提供了足夠的元數(shù)據(jù)時(shí)才起作用。否則需要顯式的提供足夠的數(shù)據(jù)。

RDBM Objects 包括 MappingSqlQuery、SqlUpdate和StoredProcedure,要求在數(shù)據(jù)訪問層初始化時(shí)創(chuàng)建可復(fù)用的、線程安全的對象。

?

1.2、package層級

Spring框架的JDBC抽象框架由四個(gè)不同的包組成:core、datasource、object以及support。

?

org.springframework.jdbc.core 包含JdbcTemplate類和其各種回調(diào)接口,以及一組相關(guān)的類。子包jdbc.core.simple包含了SimpleJdbcInsert 和 SimpleJdbcCall類。子包jdbc.core.namedparam 包含了NamedParameterJdbcTemplate類和相關(guān)支持類。

?

jdbc.datasource包含了簡化DataSource使用的工具類,以及各種簡單的DataSource實(shí)現(xiàn)(可以用于Java EE 容器之外的測試和運(yùn)行)。子包jdbc.datasource.embedded支持使用Java數(shù)據(jù)庫引擎創(chuàng)建內(nèi)嵌的數(shù)據(jù)庫,如HSQL、H2、Derby。

?

jdbc.object包含了代表RDBMS查詢、更新,以及stored-procedure(存儲(chǔ)過程)。

This approach is modeled by JDO, although objects returned by queries are naturally disconnected from the database. This higher level of JDBC abstraction depends on the lower-level abstraction in the org.springframework.jdbc.core package.

?

The org.springframework.jdbc.support package provides SQLException translation functionality and some utility classes. Exceptions thrown during JDBC processing are translated to exceptions defined in the org.springframework.dao package. This means that code using the Spring JDBC abstraction layer does not need to implement JDBC or RDBMS-specific error handling. All translated exceptions are unchecked, which gives you the option of catching the exceptions from which you can recover while allowing other exceptions to be propagated to the caller.

?

2、使用JDBC核心類來控制基本的JDBC處理和錯(cuò)誤處理

2.1、JdbcTemplate

處理資源的創(chuàng)建和釋放。執(zhí)行core JDBC工作流的基本任務(wù),例如語句的創(chuàng)建和執(zhí)行,讓應(yīng)用代碼只需要提供SQL和抽取結(jié)果即可。

?

當(dāng)你使用JdbcTemplate時(shí),你只需要實(shí)現(xiàn)回調(diào)接口們。PreparedStatementCreator回調(diào)接口會(huì)根據(jù)給定的Connection和SQL以及任何必要的參數(shù)來創(chuàng)建預(yù)處理語句。CallableStatementCreator接口也是一樣,只不過是創(chuàng)建callable語句。RowCallbackHandler接口會(huì)從ResultSet的每一行中提取值。

?

JdbcTemplate能在DAO實(shí)現(xiàn)內(nèi)使用,使用DataSource實(shí)例化。

在Spring IoC容器中,DataSource總是需要被配置的!

JdbcTemplate使用例子:

本部分提供了一些JdbcTemplate的使用例子。沒有詳盡的列出JdbcTemplate的所有功能,具體見javadoc。

查詢(SELECT)

int rowCount = this.jdbcTemplate.queryForObject("select count(*) from t_actor", Integer.class); int countOfActorsNamedJoe = this.jdbcTemplate.queryForObject("select count(*) from t_actor where first_name = ?", Integer.class, "Joe"); String lastName = this.jdbcTemplate.queryForObject("select last_name from t_actor where id = ?",new Object[]{1212L}, String.class); // 將結(jié)果映射到domain object Actor actor = this.jdbcTemplate.queryForObject("select first_name, last_name from t_actor where id = ?",new Object[]{1212L},new RowMapper<Actor>() {public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {Actor actor = new Actor();actor.setFirstName(rs.getString("first_name"));actor.setLastName(rs.getString("last_name"));return actor;}}); // 將查詢結(jié)果映射到一組domain objects。和上面相比,實(shí)際上只有等號左邊變化了。 List<Actor> actors = this.jdbcTemplate.query("select first_name, last_name from t_actor",new RowMapper<Actor>() {public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {Actor actor = new Actor();actor.setFirstName(rs.getString("first_name"));actor.setLastName(rs.getString("last_name"));return actor;}});

或者,上面的可以這樣寫:

public List<Actor> findAllActors() {return this.jdbcTemplate.query( "select first_name, last_name from t_actor", new ActorMapper()); }private static final class ActorMapper implements RowMapper<Actor> {public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {Actor actor = new Actor();actor.setFirstName(rs.getString("first_name"));actor.setLastName(rs.getString("last_name"));return actor;} }

使用JdbcTemplate更新 (INSERT/UPDATE/DELETE) --可以都使用update(..)

this.jdbcTemplate.update("insert into t_actor (first_name, last_name) values (?, ?)","Leonor", "Watling"); this.jdbcTemplate.update("update t_actor set last_name = ? where id = ?","Banjo", 5276L); this.jdbcTemplate.update("delete from actor where id = ?",Long.valueOf(actorId));

其他JdbcTemplate操作--可以使用execute(..)執(zhí)行任意SQL

this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");

調(diào)用一個(gè)簡單的存儲(chǔ)過程:

this.jdbcTemplate.update("call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",Long.valueOf(unionId));

?

JdbcTemplate 最佳實(shí)踐

JdbcTemplate 實(shí)例 是線程安全的!就是說,你只需要定義一個(gè)實(shí)例即可,隨便注入并使用!

通常的實(shí)踐是配置一個(gè)DataSource,然后將其注入到DAO類中。JdbcTemplate通過setDataSource(..)創(chuàng)建:

public class JdbcCorporateEventDao implements CorporateEventDao {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}// JDBC-backed implementations of the methods on the CorporateEventDao follow... }

相應(yīng)配置文件:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><bean id="corporateEventDao" class="com.example.JdbcCorporateEventDao"><property name="dataSource" ref="dataSource"/></bean><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><context:property-placeholder location="jdbc.properties"/></beans>

或者,使用注解配合自動(dòng)掃描。

@Repository public class JdbcCorporateEventDao implements CorporateEventDao {private JdbcTemplate jdbcTemplate;@Autowiredpublic void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}// JDBC-backed implementations of the methods on the CorporateEventDao follow... } <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- Scans within the base package of the application for @Component classes to configure as beans --><context:component-scan base-package="org.springframework.docs.test" /><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><context:property-placeholder location="jdbc.properties"/></beans>

如果使用Spring的JdbcDaoSupport類,可以讓你的DAO類繼承它,然后自動(dòng)繼承了setDataSource(..)方法。

只有在訪問多個(gè)數(shù)據(jù)庫時(shí)才需要?jiǎng)?chuàng)建多個(gè)JdbcTemplate實(shí)例!

?

2.2、NamedParameterJdbcTemplate

// some JDBC-backed DAO class... private NamedParameterJdbcTemplate namedParameterJdbcTemplate;public void setDataSource(DataSource dataSource) {this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); }public int countOfActorsByFirstName(String firstName) {String sql = "select count(*) from T_ACTOR where first_name = :first_name";SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName); // thisreturn this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class); } // some JDBC-backed DAO class... private NamedParameterJdbcTemplate namedParameterJdbcTemplate;public void setDataSource(DataSource dataSource) {this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); }public int countOfActorsByFirstName(String firstName) {String sql = "select count(*) from T_ACTOR where first_name = :first_name";Map<String, String> namedParameters = Collections.singletonMap("first_name", firstName); // 換成map了,一樣return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class); }

還可以,從domain object中獲取參數(shù) -- 不是寫入domain object!!!如下:

public class Actor {private Long id;private String firstName;private String lastName;public String getFirstName() {return this.firstName;}public String getLastName() {return this.lastName;}public Long getId() {return this.id;}// setters omitted... } // some JDBC-backed DAO class... private NamedParameterJdbcTemplate namedParameterJdbcTemplate;public void setDataSource(DataSource dataSource) {this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); }public int countOfActors(Actor exampleActor) { // 這里// notice how the named parameters match the properties of the above 'Actor' classString sql = "select count(*) from T_ACTOR where first_name = :firstName and last_name = :lastName";SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor); // 這里return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class); }

?

2.3、SQLExceptionTranslator

一個(gè)接口,其實(shí)現(xiàn)類能夠在SQLExceptions和Spring自己的org.springframework.dao.DataAccessException之間轉(zhuǎn)換。其實(shí)現(xiàn)可以是泛型的也可以是具體的。

?

SQLErrorCodeSQLExceptionTranslator 是默認(rèn)使用的實(shí)現(xiàn)。

?

?

2.4、執(zhí)行語句

執(zhí)行一個(gè)SQL語句只需要少量的代碼。

import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate;public class ExecuteAStatement {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public void doExecute() {this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");} }

2.5、運(yùn)行查詢

一些查詢方法返回單個(gè)值。使用queryForObject(..)從一行中獲取一個(gè)計(jì)數(shù)或特定的值。后者將返回的JDBC類型轉(zhuǎn)成指定的Java類型。如果類型轉(zhuǎn)換無效,會(huì)拋出InvalidDataAccessApiUsageException異常。

import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate;public class RunAQuery {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public int getCount() { // 返回intreturn this.jdbcTemplate.queryForObject("select count(*) from mytable", Integer.class);}public String getName() { // 返回Stringreturn this.jdbcTemplate.queryForObject("select name from mytable", String.class);} }

除了單個(gè)結(jié)果的查詢方法,有幾個(gè)方法返回一個(gè)列表。最泛型的方法是queryForList(..),會(huì)返回List<Map<col_name_type, col_value_type>>。如下:

private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource); }public List<Map<String, Object>> getList() {return this.jdbcTemplate.queryForList("select * from mytable"); }

返回結(jié)果類似這樣:

[{name=Bob, id=1}, {name=Mary, id=2}]

2.6、更新數(shù)據(jù)庫

下面的例子示意了更新某個(gè)特定主鍵對應(yīng)的列。參數(shù)值可以通過變參數(shù)或數(shù)組傳入。primitive類型會(huì)自動(dòng)裝箱。

import javax.sql.DataSource;import org.springframework.jdbc.core.JdbcTemplate;public class ExecuteAnUpdate {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public void setName(int id, String name) {this.jdbcTemplate.update("update mytable set name = ? where id = ?", name, id);} }

?

2.7、獲取自動(dòng)生成的鍵 auto-generated keys -- 就是mybatis的<selectKey>

JDBC 3.0標(biāo)準(zhǔn)支持使用update()方法獲取數(shù)據(jù)庫生成的主鍵。該方法使用一個(gè)PreparedStatementCreator作為其第一個(gè)參數(shù)。另一個(gè)參數(shù)是一個(gè)KeyHolder,其包含了update成功時(shí)生成的key。

下面的例子在Oracle中可以正常工作,但在其他平臺(tái)上可能無法工作。

final String INSERT_SQL = "insert into my_test (name) values(?)"; final String name = "Rob";KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(new PreparedStatementCreator() {public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {PreparedStatement ps = connection.prepareStatement(INSERT_SQL, new String[] {"id"});ps.setString(1, name);return ps;}},keyHolder);// keyHolder.getKey() now contains the generated key

?

3、控制數(shù)據(jù)庫連接

3.1、DataSource

Spring通過一個(gè)DataSource來獲取到數(shù)據(jù)庫的連接。DataSource是JDBC標(biāo)準(zhǔn)的一部分,是一個(gè)連接工廠。它允許容器或框架隱藏連接池和事務(wù)管理。

當(dāng)使用Spring的JDBC層,你是從JNDI獲取一個(gè)data source,或者,你使用第三方連接池實(shí)現(xiàn)來配置自己的data source。流行的連接池實(shí)現(xiàn)包括DBCP和C3P0. Spring中的實(shí)現(xiàn)僅用于測試目的,不提供pooling功能。

?

本部分使用Spring的DriverMangerDataSource實(shí)現(xiàn)和幾個(gè)其他實(shí)現(xiàn)。

DriverMangerDataSource 僅用于測試目的!

DriverManagerDataSource dataSource = new DriverManagerDataSource(); // 實(shí)際工作中不要使用這個(gè)!!! dataSource.setDriverClassName("org.hsqldb.jdbcDriver"); dataSource.setUrl("jdbc:hsqldb:hsql://localhost:"); dataSource.setUsername("sa"); dataSource.setPassword(""); <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/> </bean><context:property-placeholder location="jdbc.properties"/>

下例示意了針對DBCP和C3P0的基本的連接和配置:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/> </bean><context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"><property name="driverClass" value="${jdbc.driverClassName}"/><property name="jdbcUrl" value="${jdbc.url}"/><property name="user" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/> </bean><context:property-placeholder location="jdbc.properties"/>

3.2、DataSourceUtils

幫助類,提供了靜態(tài)方法從JNDI獲取連接,以及關(guān)閉連接(如有必要)。支持線程綁定的連接,例如DataSourceTransactionManager。

3.3、SmartDataSource

擴(kuò)展了DataSource接口,允許類使用它查詢連接是否應(yīng)該在某操作之后被關(guān)閉。如果你明確會(huì)復(fù)用一個(gè)連接,它會(huì)很有效率的。

3.4、AbstractDataSource

是Spring DataSource實(shí)現(xiàn)的抽象類。

3.5、SingleConnectionDataSource

是SmartDataSource的實(shí)現(xiàn),封裝了一個(gè)單獨(dú)的Connection,每次使用都不會(huì)關(guān)閉,所以不具備多線程功能。

測試類。

3.6、DriverManagerDataSource

是標(biāo)準(zhǔn)DataSource的實(shí)現(xiàn),通過bean properties配置簡單的JDBC驅(qū)動(dòng),每次返回一個(gè)新的Connection!

在測試情況以及Java EE容器之外的環(huán)境下很有用。 -- 不要在生產(chǎn)環(huán)境中使用!

3.7、TransactionAwareDataSourceProxy

是對目標(biāo)DataSource的代理,封裝了目標(biāo)DataSource to add awareness of Spring-managed transactions。從這個(gè)角度看,類似于一個(gè)Java EE服務(wù)器提供的事務(wù)性的JNDIDataSource。

-- 很少很少用到這個(gè)類!

3.8、DataSourceTransactionManager

是PlatformTransactionManager的單JDBC datasources的實(shí)現(xiàn)。它將一個(gè)特定data source的JDBC連接綁定到當(dāng)前執(zhí)行的線程,允許每個(gè)data source一個(gè)線程。

需要代碼使用DataSourceUtils.getConnection(DataSource)代替DataSource.getConnection來獲取JDBC連接。它會(huì)拋出unchecked org.springframework.dao 異常,而不是SQLExceptions。所有的框架類如JdbcTemplate都隱式的使用這種策略。

?

DataSourceTransactionManager 支持自定義隔離級別、超時(shí)時(shí)間(用于每個(gè)JDBC語句查詢)。為了支持后者,代碼中應(yīng)該使用JdbcTemplate或者DataSourceUtils.applyTransactionTimeout(..)方法來為每個(gè)創(chuàng)建的語句設(shè)置超時(shí)時(shí)間。

?

該實(shí)現(xiàn)可以替代JtaTransactionManager -- 在單資源的情況下,因?yàn)榇藭r(shí)不需要容器支持JTA。二者的切換僅僅是配置的問題。

?

3.9、NativeJdbcExtractor

有時(shí)候,你需要訪問供應(yīng)商獨(dú)有的JDBC方法,而非標(biāo)準(zhǔn)JDBC API。這時(shí)你可以使用NativeJdbcExtractor配置你的JdbcTemplate或者OracleLobHandler。

NativeJdbcExtractor 有不同變體:

  • SimpleNativeJdbcExtractor
  • C3P0NativeJdbcExtractor
  • CommonsDbcpNativeJdbcExtractor
  • JBossNativeJdbcExtractor
  • WebLogicNativeJdbcExtractor
  • WebSphereNativeJdbcExtractor
  • XAPoolNativeJdbcExtractor

多數(shù)情況下,針對為封裝的Connection對象,只需要使用SimpleNativeJdbcExtractor。

?

4、JDBC 批處理操作

當(dāng)你的批處理需要調(diào)用相同的預(yù)處理語句時(shí),多數(shù)JDBC驅(qū)動(dòng)提供了性能改進(jìn)。

4.1、使用JdbcTemplate進(jìn)行基本的批處理操作

JdbcTemplate批處理需要實(shí)現(xiàn)BatchPreparedStatementSetter接口的兩個(gè)方法,并將其作為第二個(gè)參數(shù)傳入你的batchUpdate(..)方法。使用getBatchSize()方法來提供當(dāng)前batch的尺寸。使用setValues(..)方法來為預(yù)處理語句的參數(shù)設(shè)置。 該方法會(huì)被調(diào)用n次 -- 你在getBatchSize()方法中設(shè)置的次數(shù)。例子:

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public int[] batchUpdate(final List<Actor> actors) {int[] updateCounts = jdbcTemplate.batchUpdate("update t_actor set first_name = ?, " +"last_name = ? where id = ?",new BatchPreparedStatementSetter() {public void setValues(PreparedStatement ps, int i) throws SQLException {ps.setString(1, actors.get(i).getFirstName());ps.setString(2, actors.get(i).getLastName());ps.setLong(3, actors.get(i).getId().longValue());}public int getBatchSize() {return actors.size();}});return updateCounts;}// ... additional methods }

如果你在處理一個(gè)更新stream或者從文件中讀取的stream,可能會(huì)預(yù)先設(shè)置一個(gè)batch size,但最后的batch可能不會(huì)滿足batch size。這種情況下,可以使用InterruptibleBatchPreparedStatementSetter接口,其isBatchExhausted()方法允許你判斷批處理的結(jié)束。

?

4.2、針對對象列表的批處理操作

JdbcTemplate和NamedParameterJdbcTemplate 都有另一種提供batch update的方法。不需要實(shí)現(xiàn)特定的batch接口,只需要以列表形式提供所有的參數(shù)值??蚣軙?huì)遍歷這些值并使用一個(gè)內(nèi)部的預(yù)處理語句SETTER。其API視你使用的命名參數(shù)不同而不同。For the named parameters you provide an array of SqlParameterSource, one entry for each member of the batch. You can use the SqlParameterSource.createBatch method to create this array, passing in either an array of JavaBeans or an array of Maps containing the parameter values.

例子(使用命名參數(shù)):

public class JdbcActorDao implements ActorDao {private NamedParameterTemplate namedParameterJdbcTemplate; //public void setDataSource(DataSource dataSource) {this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);}public int[] batchUpdate(final List<Actor> actors) {SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray());int[] updateCounts = namedParameterJdbcTemplate.batchUpdate("update t_actor set first_name = :firstName, last_name = :lastName where id = :id",batch);return updateCounts;}// ... additional methods }

使用JDBC的占位符:

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public int[] batchUpdate(final List<Actor> actors) {List<Object[]> batch = new ArrayList<Object[]>();for (Actor actor : actors) {Object[] values = new Object[] {actor.getFirstName(),actor.getLastName(),actor.getId()};batch.add(values);}int[] updateCounts = jdbcTemplate.batchUpdate("update t_actor set first_name = ?, last_name = ? where id = ?", // ? 占位符 batch);return updateCounts;}// ... additional methods }

上面兩個(gè)例子最后都會(huì)返回一個(gè)int數(shù)組,每個(gè)值都代表一條語句執(zhí)行后影響的行數(shù)。如果不可用,會(huì)返回-2。

?

4.3、多個(gè)批處理的批處理操作

當(dāng)批處理非常大時(shí),你可能想將其拆分成幾個(gè)小的批處理。當(dāng)然,你可以使用上面的方法,多次調(diào)用batchUpdate方法即可,但這里有一個(gè)更方便的方法。該方法除了使用SQL語句,還需要一個(gè)對象的集合 -- 包含了參數(shù)、每個(gè)batch中update的數(shù)量、以及一個(gè)ParameterizedPreparedStatementSetter 來為參數(shù)設(shè)值??蚣軙?huì)遍歷提供的值,并將update調(diào)用拆分成指定大小的batch中。

例子:

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public int[][] batchUpdate(final Collection<Actor> actors) {int[][] updateCounts = jdbcTemplate.batchUpdate("update t_actor set first_name = ?, last_name = ? where id = ?",actors,100, // this, size of each batchnew ParameterizedPreparedStatementSetter<Actor>() { // thispublic void setValues(PreparedStatement ps, Actor argument) throws SQLException {ps.setString(1, argument.getFirstName());ps.setString(2, argument.getLastName());ps.setLong(3, argument.getId().longValue());}});return updateCounts;}// ... additional methods }

最終結(jié)果是int數(shù)組的數(shù)組。不再解釋。

?

5、使用SimpleJdbc類來簡化JDBC操作

SimpleJdbcInsert和SimpleJdbcCall類利用了可以從JDBC驅(qū)動(dòng)獲取的數(shù)據(jù)庫的元數(shù)據(jù),從而提供了簡化的配置。

?

5.1、使用SimpleJdbcInsert 插入數(shù)據(jù)

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;private SimpleJdbcInsert insertActor; // thispublic void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);this.insertActor = new SimpleJdbcInsert(dataSource).withTableName("t_actor"); // here!!! }public void add(Actor actor) {Map<String, Object> parameters = new HashMap<String, Object>(3);parameters.put("id", actor.getId());parameters.put("first_name", actor.getFirstName());parameters.put("last_name", actor.getLastName());insertActor.execute(parameters);}// ... additional methods }

5.2、使用SimpleJdbcInsert獲取自動(dòng)生成的鍵

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;private SimpleJdbcInsert insertActor;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);this.insertActor = new SimpleJdbcInsert(dataSource).withTableName("t_actor") // here.usingGeneratedKeyColumns("id"); // here }public void add(Actor actor) {Map<String, Object> parameters = new HashMap<String, Object>(2);parameters.put("first_name", actor.getFirstName());parameters.put("last_name", actor.getLastName());Number newId = insertActor.executeAndReturnKey(parameters); // here actor.setId(newId.longValue());}// ... additional methods }

如果返回多個(gè)自動(dòng)生成的鍵,可以使用executeAndReturnKeyHolder,這會(huì)返回一個(gè)KeyHolder。

?

5.3、為SimpleJdbcInsert指定列

就是限制插入的列。

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;private SimpleJdbcInsert insertActor;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);this.insertActor = new SimpleJdbcInsert(dataSource).withTableName("t_actor").usingColumns("first_name", "last_name") // here.usingGeneratedKeyColumns("id");}public void add(Actor actor) {Map<String, Object> parameters = new HashMap<String, Object>(2);parameters.put("first_name", actor.getFirstName());parameters.put("last_name", actor.getLastName());Number newId = insertActor.executeAndReturnKey(parameters);actor.setId(newId.longValue());}// ... additional methods }

5.4、使用SqlParameterSource提供參數(shù)值

使用Map提供參數(shù)值很不錯(cuò),但不是最方便的。Spring提供了一組SqlParameterSource接口的實(shí)現(xiàn),很不錯(cuò)。第一個(gè)是BeanPropertySqlParameterSource,適用于JavaBean類。例子:

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;private SimpleJdbcInsert insertActor;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);this.insertActor = new SimpleJdbcInsert(dataSource).withTableName("t_actor").usingGeneratedKeyColumns("id");}public void add(Actor actor) {SqlParameterSource parameters = new BeanPropertySqlParameterSource(actor); // hereNumber newId = insertActor.executeAndReturnKey(parameters);actor.setId(newId.longValue());}// ... additional methods }

另一個(gè)是MapSqlParameterSource,重裝了一個(gè)Map,但提供了更方便的addValue方法--可以鏈?zhǔn)骄幊?#xff01;如下:

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;private SimpleJdbcInsert insertActor;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);this.insertActor = new SimpleJdbcInsert(dataSource).withTableName("t_actor").usingGeneratedKeyColumns("id");}public void add(Actor actor) {SqlParameterSource parameters = new MapSqlParameterSource() // this.addValue("first_name", actor.getFirstName()) // 鏈?zhǔn)骄幊?/span>.addValue("last_name", actor.getLastName()); // 鏈?zhǔn)骄幊?/span>Number newId = insertActor.executeAndReturnKey(parameters);actor.setId(newId.longValue());}// ... additional methods }

?

5.5、使用SimpleJdbcCall調(diào)用存儲(chǔ)過程

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-simple-jdbc-call-1

?

5.6、為SimpleJdbcCall顯式聲明參數(shù)

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-simple-jdbc-call-2

?

5.7、如何定義SqlParameter

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-params

為了SimpleJdbc類還有RDBMS的操作類定義參數(shù),可以使用SqlParameter或其任一子類。通常需要在構(gòu)造器中指定參數(shù)名和SQL類型。SQL類型使用java.sql.Types中的常量。

new SqlParameter("in_id", Types.NUMERIC),new SqlOutParameter("out_first_name", Types.VARCHAR),

略。。。

?

5.8、使用SimpleJdbcCall調(diào)用stored function

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-simple-jdbc-call-3

?

5.9、從SimpleJdbcCall返回ResultSet/REF 游標(biāo)

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-simple-jdbc-call-4

?

6、將JDBC操作模型化為Java對象

org.springframework.jdbc.object

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-object

6.1、SqlQuery

6.2、MappingSqlQuery

6.3、SqlUpdate

6.4、StoredProcedure

?

?

7、參數(shù)和數(shù)據(jù)值處理的常見問題

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-parameter-handling

7.1、為參數(shù)提供SQL type信息

一般,Spring是基于傳入的參數(shù)類型決定參數(shù)的SQL type。但還可以顯式的提供SQL type。有時(shí)候?yàn)榱苏_設(shè)置NULL值,這樣做很有必要。

有以下幾種方式:

  • JdbcTemplate的很多update和query方法會(huì)接收一個(gè)額外的參數(shù):int數(shù)組形式。該數(shù)組用于表明相應(yīng)參數(shù)的SQL類型,其值來自java.sql.Types類的常量。
  • 還可以使用SqlParameterValue類來封裝需要額外信息的參數(shù)值。為每個(gè)值創(chuàng)建一個(gè)實(shí)例,將SQL type和參數(shù)值傳入構(gòu)造器。You can also provide an optional scale parameter for numeric values.
  • 當(dāng)使用命名參數(shù)時(shí),使用SqlParameterSource類的子類:BeanPropertySqlParameterSource 或 MapSqlParameterSource。它們都有為任意命名參數(shù)值注冊SQL type的方法。

7.2、處理BLOB 和 CLOB對象

你可以在數(shù)據(jù)庫中存儲(chǔ)圖像、其他二進(jìn)制數(shù)據(jù),還有大量的文本。這些大對象稱為:BLOB(Binary Large Object) -- 針對二進(jìn)制數(shù)據(jù);CLOB (Character Large Object) -- 針對字符數(shù)據(jù)。在Spring中你可以使用JdbcTemplate處理這些大對象 (In Spring you can handle these large objects by using the JdbcTemplate directly and also when using the higher abstractions provided by RDBMS Objects and the SimpleJdbc classes.)。所有這些途徑都是用了LobHandler接口的實(shí)現(xiàn)。LobHandler可以訪問LobCreator類以創(chuàng)建新的LOB對象--使用getLobCreator()方法,從而插入數(shù)據(jù)庫。

LobCreator/LobHandler 為LOB的輸入輸出提供下列支持:

  • BLOB
    • byte[] -- getBlobAsBytes, setBlobAsBytes
    • InputStream -- getBlobAsBinaryStream, setBlobAsBinaryStream
  • CLOB
    • String -- getClobAsString, setClobAsString
    • InputStream -- getClobAsAsciiStream, setClobAsAsciiStream
    • Reader -- getClobAsCharacterStream, setClobAsCharacterStream

?

下面的例子使用了JdbcTemplate以及AbstractLobCreatingPreparedStatementCallback的一個(gè)實(shí)現(xiàn)。它實(shí)現(xiàn)了setValues方法,該方法提供了一個(gè)LobCreator可以為LOB列設(shè)值。

下面的例子假定已經(jīng)有一個(gè)變量lobHandler,且已經(jīng)設(shè)置成DefaultLobHandler的實(shí)例。

final File blobIn = new File("spring2004.jpg"); final InputStream blobIs = new FileInputStream(blobIn); final File clobIn = new File("large.txt"); final InputStream clobIs = new FileInputStream(clobIn); final InputStreamReader clobReader = new InputStreamReader(clobIs); jdbcTemplate.execute("INSERT INTO lob_table (id, a_clob, a_blob) VALUES (?, ?, ?)",new AbstractLobCreatingPreparedStatementCallback(lobHandler) { // 1protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException {ps.setLong(1, 1L);lobCreator.setClobAsCharacterStream(ps, 2, clobReader, (int)clobIn.length()); // 2lobCreator.setBlobAsBinaryStream(ps, 3, blobIs, (int)blobIn.length()); // 3}} ); blobIs.close(); clobReader.close();

  • Pass in the lobHandler that in this example is a plain DefaultLobHandler.
  • Using the method setClobAsCharacterStream, pass in the contents of the CLOB.
  • Using the method setBlobAsBinaryStream, pass in the contents of the BLOB.
  • If you invoke the setBlobAsBinaryStream, setClobAsAsciiStream, or setClobAsCharacterStream method on the LobCreator returned from DefaultLobHandler.getLobCreator(), you can optionally specify a negative value for the contentLength argument. If the specified content length is negative, the DefaultLobHandler will use the JDBC 4.0 variants of the set-stream methods without a length parameter; otherwise, it will pass the specified length on to the driver.

    上面的例子是寫入LOB數(shù)據(jù),下面看看讀取LOB數(shù)據(jù):

    List<Map<String, Object>> l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table",new RowMapper<Map<String, Object>>() {public Map<String, Object> mapRow(ResultSet rs, int i) throws SQLException {Map<String, Object> results = new HashMap<String, Object>();String clobText = lobHandler.getClobAsString(rs, "a_clob"); // 1 results.put("CLOB", clobText); byte[] blobBytes = lobHandler.getBlobAsBytes(rs, "a_blob"); // 2 results.put("BLOB", blobBytes); return results; } });

    Using the method getClobAsString, retrieve the contents of the CLOB.

    Using the method getBlobAsBytes, retrieve the contents of the BLOB.

    ?

    7.3、為IN語句傳入值列表

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-in-clause

    ?

    7.4、為存儲(chǔ)過程的調(diào)用處理復(fù)雜類型

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-complex-types

    ?

    8、內(nèi)嵌數(shù)據(jù)庫支持

    原生支持HSQL, H2, Derby??梢詳U(kuò)展。

    8.1、為什么使用內(nèi)嵌數(shù)據(jù)庫?

    開發(fā)階段很有用,因?yàn)槠漭p量級特性。易配置,啟動(dòng)快,便于測試,以及快速的改進(jìn)SQL。

    8.2、使用Spring XML創(chuàng)建內(nèi)嵌數(shù)據(jù)庫

    如果想將內(nèi)嵌數(shù)據(jù)庫實(shí)例暴露到Spring的ApplicationContext中作為一個(gè)bean,需要使用spring-jdbc命名空間的embedded-database標(biāo)簽:

    <jdbc:embedded-database id="dataSource" generate-name="true"><jdbc:script location="classpath:schema.sql"/><jdbc:script location="classpath:test-data.sql"/> </jdbc:embedded-database>上面的配置會(huì)創(chuàng)建一個(gè)內(nèi)嵌的HSQL數(shù)據(jù)庫,并執(zhí)行schema.sql和test-data.sql中的SQL語句。

    另外,作為最佳實(shí)踐,內(nèi)嵌數(shù)據(jù)庫會(huì)被賦予一個(gè)獨(dú)特的生成的名字。內(nèi)嵌數(shù)據(jù)庫在Spring容器中是一種javax.sql.DataSource類型的bean,可以注入任何dao中。

    8.3、編碼式創(chuàng)建一個(gè)內(nèi)嵌數(shù)據(jù)庫

    類似這樣:

    EmbeddedDatabase db = new EmbeddedDatabaseBuilder() // 這貨.generateUniqueName(true).setType(H2).setScriptEncoding("UTF-8").ignoreFailedDrops(true).addScript("schema.sql").addScripts("user_data.sql", "country_data.sql").build();// perform actions against the db (EmbeddedDatabase extends javax.sql.DataSource) db.shutdown()

    還可以這樣:

    @Configuration public class DataSourceConfig {@Beanpublic DataSource dataSource() {return new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(H2).setScriptEncoding("UTF-8").ignoreFailedDrops(true).addScript("schema.sql").addScripts("user_data.sql", "country_data.sql").build();} }

    8.4、選擇內(nèi)嵌數(shù)據(jù)庫類型

    使用HSQL

    Spring支持HSQL 1.8.0及以上版本。如果沒有指定,默認(rèn)就是HSQL。需要指定的話,將embedded-database標(biāo)簽的type屬性設(shè)值為HSQL即可。

    如果使用builder API,調(diào)用setType(EmbeddedDatabaseType.HSQL) 即可。

    其他:H2,Derby。類似HSQL。

    8.5、使用內(nèi)嵌數(shù)據(jù)庫測試數(shù)據(jù)訪問邏輯

    public class DataAccessIntegrationTestTemplate {private EmbeddedDatabase db;@Beforepublic void setUp() {// creates an HSQL in-memory database populated from default scripts// classpath:schema.sql and classpath:data.sqldb = new EmbeddedDatabaseBuilder().generateUniqueName(true).addDefaultScripts().build();}@Testpublic void testDataAccess() {JdbcTemplate template = new JdbcTemplate(db);template.query( /* ... */ );}@Afterpublic void tearDown() {db.shutdown();}}

    Embedded databases provide a lightweight way to test data access code. The following is a data access integration test template that uses an embedded database. Using a template like this can be useful for one-offs when the embedded database does not need to be reused across test classes. However, if you wish to create an embedded database that is shared within a test suite, consider using the Spring TestContext Framework and configuring the embedded database as a bean in the Spring ApplicationContext as described in Section 19.8.2, “Creating an embedded database using Spring XML” and Section 19.8.3, “Creating an embedded database programmatically”.

    8.6、為內(nèi)嵌數(shù)據(jù)庫生成一個(gè)唯一的名字

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-embedded-database-unique-names

    8.7、擴(kuò)展內(nèi)嵌數(shù)據(jù)庫支持

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-embedded-database-extension

    ?

    ?

    9、初始化一個(gè)DataSource

    org.springframework.jdbc.datasource.init包提供了初始化已有DataSource的支持。內(nèi)嵌數(shù)據(jù)庫支持 提供了為一個(gè)應(yīng)用創(chuàng)建和初始化一個(gè)DataSource的選項(xiàng),但是,有時(shí)候你需要在服務(wù)器或者其他地方初始化一個(gè)實(shí)例。

    9.1、使用Spring XML初始化一個(gè)數(shù)據(jù)庫

    <jdbc:initialize-database data-source="dataSource"><jdbc:script location="classpath:com/foo/sql/db-schema.sql"/><jdbc:script location="classpath:com/foo/sql/db-test-data.sql"/> </jdbc:initialize-database>

    該數(shù)據(jù)庫初始化器的默認(rèn)行為是無條件的執(zhí)行提供的腳本。這通常不是你想要的,例如,如果你要針對一個(gè)已有數(shù)據(jù)的數(shù)據(jù)庫進(jìn)行初始化。偶然刪除數(shù)據(jù)的可能可以通過以下常見模式(先創(chuàng)建表,再插入數(shù)據(jù),如果已經(jīng)存在表,那第一步就會(huì)失敗)來降低。

    ?

    然而,為了獲取針對已有數(shù)據(jù)的創(chuàng)建和刪除的更多控制,XML命名空間提供了一些額外的選項(xiàng)。第一個(gè)選項(xiàng)就是切換是否初始化。這可以根據(jù)環(huán)境來設(shè)置(例如從系統(tǒng)properties中獲取一個(gè)boolean值),如下:

    <jdbc:initialize-database data-source="dataSource"enabled="#{systemProperties.INITIALIZE_DATABASE}"><jdbc:script location="..."/> </jdbc:initialize-database>

    The second option to control what happens with existing data is to be more tolerant of failures. 你可以控制初始化器的能力,讓其在執(zhí)行scripts中的SQL時(shí)忽略特定錯(cuò)誤。例如:

    <jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS"><jdbc:script location="..."/> </jdbc:initialize-database>

    上面的例子是說,有時(shí)候我們期望scripts能夠在一個(gè)空的數(shù)據(jù)庫上執(zhí)行 ,scripts中的一些DROP語句會(huì)執(zhí)行失敗。這些失敗的SQL DROP語句會(huì)被忽略,但其他失敗會(huì)導(dǎo)致異常。當(dāng)你的SQL dialect不支持 DROP ... IF EXISTS ,但你又想在重建數(shù)據(jù)前無條件的清除所有測試數(shù)據(jù)時(shí),這會(huì)很有用。

    ignore-failures 選項(xiàng),可以被設(shè)置為NONE(默認(rèn))、DROPS、或 ALL。

    每個(gè)語句都應(yīng)以分號間隔,或者完全不使用分號,而用換行代替。你可以控制它:

    <jdbc:initialize-database data-source="dataSource" separator="@@"><jdbc:script location="classpath:com/foo/sql/db-schema.sql" separator=";"/><jdbc:script location="classpath:com/foo/sql/db-test-data-1.sql"/><jdbc:script location="classpath:com/foo/sql/db-test-data-2.sql"/> </jdbc:initialize-database>

    上面是用 @@作為通用的分隔符,又給db-schema.sql設(shè)置了分號分隔符。

    如果需要更多控制,使用DataSourceInitializer即可。

    ?

    依賴數(shù)據(jù)庫的其他組件的初始化

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-client-component-initialization

    數(shù)據(jù)庫初始化器依賴于一個(gè)DataSource實(shí)例,且會(huì)執(zhí)行在其初始化回調(diào)(類似@PostConstruct)中提供的scripts。如果其他beans依賴相同的data source,并也在初始化回調(diào)中使用它,那么可能會(huì)導(dǎo)致問題,因?yàn)閿?shù)據(jù)還沒有初始化!常見的例子是在應(yīng)用啟動(dòng)時(shí)就迫切的初始化并加載數(shù)據(jù)的緩存。

    圍繞這個(gè)問題,你有兩個(gè)選擇:改變你的緩存初始化策略,不要迫切初始化,而是延遲初始化,或者確保數(shù)據(jù)庫初始化器已經(jīng)初始化了。

    第一個(gè)選擇可能很簡單 -- 如果你負(fù)責(zé)這個(gè)應(yīng)用。一些建議:

    • 讓緩存懶初始化--第一次使用時(shí)再初始化。
    • 讓你的緩存或者初始化緩存的組件實(shí)現(xiàn)Lifecycle或SmartLifecycle。當(dāng)應(yīng)用上下文啟動(dòng)時(shí),SmartLifecyle會(huì)被自動(dòng)啟動(dòng)--如果它的autoStartup被設(shè)置了,可以在該上下文中手動(dòng)調(diào)用ConfigurableApplicationContext.start()來啟動(dòng)Lifecycle
    • 使用ApplicationEvent或類似的觀察者機(jī)制來觸發(fā)緩存初始化。ContextRefreshedEvent通常是個(gè)很有用的鉤子。

    第二個(gè)選擇可能同樣簡單。一些建議:

    • 依賴Spring BeanFactory的默認(rèn)行為--beans以注冊順序被初始化。你可以很簡單的安排順序--一組<import/>,讓數(shù)據(jù)庫放在前面。
    • 分離DataSource和使用其的業(yè)務(wù)組件,通過將它們放在不同的ApplicationContext實(shí)例中來控制它們的啟動(dòng)順序。--例如,父上下文包含DataSource,子上下文包含業(yè)務(wù)組件。這種結(jié)構(gòu)在Spring web應(yīng)用中很常見,但可用于更多地方。

    轉(zhuǎn)載于:https://www.cnblogs.com/larryzeal/p/5997550.html

    總結(jié)

    以上是生活随笔為你收集整理的Spring 4 官方文档学习(十)数据访问之JDBC的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。