spring-JDBC
Spring JDBC 抽象了JDBC API,下表標注X的表示在操作序列中,Spring和開發人員需要關注的操作
| 定義連接串 | ? | X |
| Open連接 | X | ? |
| 指定SQL語句 | ? | X |
| 定義參數和參數值 | ? | X |
| prepare和執行語句 | X | ? |
| 循環處理結果集 | X | ? |
| 每行結果記錄怎么處理 | ? | X |
| 處理異常 | X | ? |
| 處理事務 | X | ? |
| 關閉連接,statement,結果集 | X | ? |
不同的JDBC 訪問方式
Spring JDBC 提供了幾種方法,以運用不同類與數據庫的接口。除了JdbcTemplate之外,新的SimpleJdbcinsert 和SimpleJdbcCall兩個類通過利用JDBC驅動提供的數據庫元數據來簡化JDBC操作,而RDBMS Object 樣式采用了更類似于JDO Query 設計的面向對象的方法。
- JdbcTemplate
JdbcTemplate是最經典的Spring JDBC 方法。這是一種底層的方法,其他方法內部都借助于JdbcTemplate 來完成。
- NamedParameterJdbcTemplate
NamedParameterJdbcTemplate 封裝了JdbcTemplate以提供命名參數,而不是使用傳統的JDBC "?"占位符。當一個SQL 語句有多個參數時,這種方法則呈現出了更好的可良性和易用性。
- SimpleJdbclnsert 和SimpleJdbcCall
SimpleJdbcinsert 和SimpleJdbcCa ll 優化數據庫元數據,以限制必要配置的數量。這種方法簡化了編碼,只需要提供表或存儲過程的名稱及與列名匹配的參數映射。這僅在數據庫提供足夠的元數據時有效。如果數據庫不提供此元數據, 則必須提供參數的顯式配置。
- RDBMS Object
RDBMS Object 包括MappingSqlQuery 、SqlUpdate 和StoredProcedure ,需要在數據訪問層初始化期間建立可重用的且是線程安全的對象。此方法在JDO Query之后建模,可以在其中定義查詢字符串、聲明參數并編譯查詢。一旦這樣做,執行方法可以多次調用傳人的各種參數值。
JDBC包層次結構
Spring JDBC 由4個不同的包構成,分別為core 、datasource、object和support 。
-
core:
org.springframework.jdbc.core 包包含JdbcTemplate和大量callback 接口以及相關類。org.springframework.jdbc.core.simple 包含 SimpleJdbcInsert 和SimpleJdbcCall classes。 org.springframework.jdbc.core.namedparam 包含NamedParameterJdbcTemplate 以及相關支持類。
-
datasource:
?org.springframework.jdbc.datasource包數據訪問的實用工具類和多種DataSource的實現類,可以在Java EE 容器外測試JDBC代碼。 org.springfamework.jdbc.datasource.embedded子包提供了使用Java 數據庫引擎( 如HSQL 、H2 和Derby )創建嵌入式數據庫的支持
-
object:
org.springframework.jdbc.object 為對象包,以面向對象的方式訪問數據庫。它允許執行查詢并返回結果作為業務對象,可以在數據表的列和業務對象的屬性之間映射查詢結果。.
-
support:
?org.springframework.jdbc.support為支持包,提供了SQLException 轉換功能和一些實用工具類,均是core包和object包的支持類。.
JDBC Core類
JdbcTemplate
JdbcTemplate類是線程安全的。
JdbcTemplate它用于處理資源的創建和釋放,可以避免開發人員常見的JDBC使用錯誤,如忘記關閉連接。它執行核心JDBC工作流的基本任務,如語句創建和執行,使應用程序代碼提供SQL并提取結果。JdbcTemplate可以
- 執行Sql查詢
- update語句以及存儲過程調用
- 迭代ResultSet返回結果。
- 捕獲異常并轉換為DAO異常。
使用JdbcTemplate 時,只需要實現回調接口即可。PreparedStatementCreator 回調接口根據該類提供的Connection創建一個準備好的語句,提供SQL和任何必需的參數。CallableStatementCreator接口也是如此,該接口創建可調用語句。RowCallbackHandler接口從ResultSet的每一行提取值。
JdbcTemplate可以通過直接實例化DataSource引用在DAO實現中使用,或者在Spring IoC容器中配置并作為bean引用提供給DAO 。
DataSource 應始終在Spring IoC 容器中配置為一個bean 。在上述的第一種情況下,bean 直接提供給服務;在第二種情況下,它被提供給準備好的模板。
查詢(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);
//查詢和填充單個域對象,實現RowMapper類
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;
??????????? }
??????? });???????
//查詢和填充多個域對象實現RowMapper類
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;
??????????? }
??????? });???
Updating (INSERT, UPDATE, and DELETE)
//insert
this.jdbcTemplate.update(
??????? "insert into t_actor (first_name, last_name) values (?, ?)",
??????? "Leonor", "Watling");
//update
??????? this.jdbcTemplate.update(
??????? "update t_actor set last_name = ? where id = ?",
??????? "Banjo", 5276L);
其他操作
可以使用execute(..)方法來執行任意SQL ,因此該方法通常用于DDL 語句。
??????? this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
???????
this.jdbcTemplate.update(
??????? "call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
??????? Long.valueOf(unionId));
NamedParameterJdbcTemplate
在經典的JDBC用法中,SQL參數是用占位輪“?”來表示的,這會受到位置的限制。這種方式的問題在于,一旦參數的順序發生變化,就必須改變參數綁定。在Spring JDBC框架中,綁定SQL 參數的另一種選擇是使用命名參數( named parameter ) 。
public int countOfActorsByFirstName(String firstName) {
??? String sql = "select count(*) from T_ACTOR where first_name = :first_name";
??? SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName);
??? return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
}
// 基于Map的方式
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);
??? return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters,? Integer.class);
}
與NamedParameterJdbcTemplate相關的一個很好的功能是SqlParameterSource接口,SqlParameterSource是NamedParameterJdbcTemplate 的命名參數值的來源。
MapSqlParameterSource類是一個非常簡單的實現,它只是一個圍繞java.util.Map的適配器,其中鍵是參數名稱,值是參數值。
另一個SqlParameterSource 實現是BeanPropertySqlParameterSource類。這個類包裝了一個任意的JavaBean ,并使用包裝的JavaBean的屬性作為命名參數值的來源。
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;
??? }
}
//屬性作為參數源
public int countOfActors(Actor exampleActor) {
??? String 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);
}
SQLExceptionTranslator
SQLExceptionTranslator是一個接口,其實現類可以用于SQLExceptions和Spring 自己的org.springframework.dao.DataAccessException 之間進行轉換。
SQLErrorCodeSQLExceptionTranslator是SQLExceptionTranslator的默認實現。該實現使用特定的供應商代碼,它比SQLState實現更精確。錯誤代碼轉換基于JavaBean 類型類SQLErrorCodes中保存的代碼。該類由SQLErrorCodesFactory 創建和填充,顧名思義,它是一個根據名為sql-error-codes.xml的配置文件內容創建SQLErrorCodes 的工廠。該文件使用供應商代碼填充,供應商代碼從DatabaseMetaData獲取DatabaseProductName。
public class CustomSQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator {
??? protected DataAccessException customTranslate(String task, String sql, SQLException sqlex) {
// 對錯誤碼:-12345特殊處理
??????? if (sqlex.getErrorCode() == -12345) {
??????????? return new DeadlockLoserDataAccessException(task, sqlex);
??????? }
??????? return null;
??? }
}
檢索自動生成的主鍵
update()方法支持檢索由數據庫生成的主鍵。這種支持是JDBC3.0標準的一部分。該方法將PreparedStatementCreator 作為其第一個參數,需要指定插入語句。另一個參數是KeyHolder,它包含從更新成功返回時生成的主鍵。
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
數據庫連接
DataSource
Spring通過一個DataSource(數據源)獲得與數據庫的連接。在使用Spring的JDBC時,可以從JNDI獲取數據源,或者使用第三方提供的連接池實現來配置自己的數據源。流行的實現是Apache Jakarta Commons DBCP 和C3P0 。Spring 發行版本中的實現僅用于測試,并未提供連接池方案。所以在使用Spring的DriverManagerDataSource類時,僅用于測試目的,因為它不提供連接池的方案,在執行多個連接請求時性能較差。
- 代碼方式:
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:hsql://localhost:");
dataSource.setUsername("sa");
dataSource.setPassword("");
- Spring方式:
<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
<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"/>
- C3P0
<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"/>
?
?
?
更多信息:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#jdbc
?
總結
以上是生活随笔為你收集整理的spring-JDBC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring-DAO
- 下一篇: spring-tx