天天看點

spring-JDBC不同的JDBC 通路方式JDBC包層次結構JDBC Core類資料庫連接配接

Spring JDBC 抽象了JDBC API,下表标注X的表示在操作序列中,Spring和開發人員需要關注的操作

操作 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

繼續閱讀