# 【第七章】 對JDBC的支持 之 7.3 關系數據庫操作對象化 ——跟我學spring3
### 7.3.1? 概述
所謂**關系數據庫對象化其實就是用面向對象方式表示關系數據庫操作,從而可以復用。**
Spring JDBC框架將數據庫操作封裝為一個RdbmsOperation,該對象是線程安全的、可復用的對象,是所有數據庫對象的父類。而SqlOperation繼承了RdbmsOperation,代表了數據庫SQL操作,如select、update、call等,如圖7-4所示。

圖7-4 關系數據庫操作對象化支持類
數據庫操作對象化只要有以下幾種類型,所以類型是線程安全及可復用的:
* **查詢:**將數據庫操作select封裝為對象,查詢操作的基類是SqlQuery,所有查詢都可以使用該類表示,Spring JDBC還提供了一些更容易使用的MappingSqlQueryWithParameters和MappingSqlQuery用于將結果集映射為Java對象,查詢對象類還提供了兩個擴展UpdatableSqlQuery和SqlFunction;
* **更新:**即增刪改操作,將數據庫操作insert 、update、delete封裝為對象,增刪改基類是SqlUpdate,當然還提供了BatchSqlUpdate用于批處理;
* **存儲過程及函數:**將存儲過程及函數調用封裝為對象,基類是SqlCall類,提供了StoredProcedure實現。
### 7.3.2? 查詢
**1)SqlQuery:**需要覆蓋如下方法來定義一個RowMapper,其中parameters參數表示命名參數或占位符參數值列表,而context是由用戶傳入的上下文數據。
```
RowMapper<T> newRowMapper(Object[] parameters, Map context)
```
SqlQuery提供兩類方法:
* execute及executeByNamedParam方法:用于查詢多行數據,其中executeByNamedParam用于支持命名參數綁定參數;
* findObject及findObjectByNamedParam方法:用于查詢單行數據,其中findObjectByNamedParam用于支持命名參數綁定。
演示一下SqlQuery如何使用:
```
@Test
public void testSqlQuery() {
SqlQuery query = new UserModelSqlQuery(jdbcTemplate);
List<UserModel> result = query.execute("name5");
Assert.assertEquals(0, result.size());
}
```
從測試代碼可以SqlQuery使用非常簡單,創建SqlQuery實現對象,然后調用相應的方法即可,接下來看一下SqlQuery實現:
```
package cn.javass.spring.chapter7;
//省略import
public class UserModelSqlQuery extends SqlQuery<UserModel> {
public UserModelSqlQuery(JdbcTemplate jdbcTemplate) {
//super.setDataSource(jdbcTemplate.getDataSource());
super.setJdbcTemplate(jdbcTemplate);
super.setSql("select * from test where name=?");
super.declareParameter(new SqlParameter(Types.VARCHAR));
compile();
}
@Override
protected RowMapper<UserModel> newRowMapper(Object[] parameters, Map context) {
return new UserRowMapper();
}
}
```
從測試代碼可以看出,具體步驟如下:
一、setJdbcTemplate/ setDataSource:首先設置數據源或JdbcTemplate;
二、setSql("select * from test where name=?"):定義sql語句,所以定義的sql語句都將被編譯為PreparedStatement;
三、declareParameter(new SqlParameter(Types.VARCHAR)):對PreparedStatement參數描述,使用SqlParameter來描述參數類型,支持命名參數、占位符描述;
對于命名參數可以使用如new SqlParameter("name", Types.VARCHAR)描述;注意占位符參數描述必須按占位符參數列表的順序進行描述;
四、編譯:可選,當執行相應查詢方法時會自動編譯,用于將sql編譯為PreparedStatement,對于編譯的SqlQuery不能再對參數進行描述了。
五、以上步驟是不可變的,必須按順序執行。
**2)MappingSqlQuery:**用于簡化SqlQuery中RowMapper創建,可以直接在實現mapRow(ResultSet rs, int rowNum)來將行數據映射為需要的形式;
MappingSqlQuery所有查詢方法完全繼承于SqlQuery。
演示一下MappingSqlQuery如何使用:
```
@Test
public void testMappingSqlQuery() {
jdbcTemplate.update("insert into test(name) values('name5')");
SqlQuery<UserModel> query = new UserModelMappingSqlQuery(jdbcTemplate);
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("name", "name5");
UserModel result = query.findObjectByNamedParam(paramMap);
Assert.assertNotNull(result);
}
```
MappingSqlQuery使用和SqlQuery完全一樣,創建MappingSqlQuery實現對象,然后調用相應的方法即可,接下來看一下MappingSqlQuery實現,findObjectByNamedParam方法用于執行命名參數查詢:
```
package cn.javass.spring.chapter7;
//省略import
public class UserModelMappingSqlQuery extends MappingSqlQuery<UserModel> {
public UserModelMappingSqlQuery(JdbcTemplate jdbcTemplate) {
super.setDataSource(jdbcTemplate.getDataSource());
super.setSql("select * from test where name=:name");
super.declareParameter(new SqlParameter("name", Types.VARCHAR));
compile();
}
@Override
protected UserModel mapRow(ResultSet rs, int rowNum) throws SQLException {
UserModel model = new UserModel();
model.setId(rs.getInt("id"));
model.setMyName(rs.getString("name"));
return model;
}
}
```
和SqlQuery唯一不同的是使用mapRow來講每行數據轉換為需要的形式,其他地方完全一樣。
1)??**UpdatableSqlQuery:**提供可更新結果集查詢支持,子類實現updateRow(ResultSet rs, int rowNum, Map context)對結果集進行更新。
2)??**GenericSqlQuery:**提供setRowMapperClass(Class rowMapperClass)方法用于指定RowMapper實現,在此就不演示了。具體請參考testGenericSqlQuery()方法。
3)??**SqlFunction:**SQL“函數”包裝器,用于支持那些返回單行結果集的查詢。該類主要用于返回單行單列結果集。
```
@Test
public void testSqlFunction() {
jdbcTemplate.update("insert into test(name) values('name5')");
String countSql = "select count(*) from test";
SqlFunction<Integer> sqlFunction1 = new SqlFunction<Integer>(jdbcTemplate.getDataSource(), countSql);
Assert.assertEquals(1, sqlFunction1.run());
String selectSql = "select name from test where name=?";
SqlFunction<String> sqlFunction2 = new SqlFunction<String>(jdbcTemplate.getDataSource(), selectSql);
sqlFunction2.declareParameter(new SqlParameter(Types.VARCHAR));
String name = (String) sqlFunction2.runGeneric(new Object[] {"name5"});
Assert.assertEquals("name5", name);
}
```
如代碼所示,SqlFunction初始化時需要DataSource和相應的sql語句,如果有參數需要使用declareParameter對參數類型進行描述;run方法默認返回int型,當然也可以使用runGeneric返回其他類型,如String等。
### 7.3.3? 更新
SqlUpdate類用于支持數據庫更新操作,即增刪改(insert、delete、update)操作,該方法類似于SqlQuery,只是職責不一樣。
SqlUpdate提供了update及updateByNamedParam方法用于數據庫更新操作,其中updateByNamedParam用于命名參數類型更新。
演示一下SqlUpdate如何使用:
```
package cn.javass.spring.chapter7;
//省略import
public class InsertUserModel extends SqlUpdate {
public InsertUserModel(JdbcTemplate jdbcTemplate) {
super.setJdbcTemplate(jdbcTemplate);
super.setSql("insert into test(name) values(?)");
super.declareParameter(new SqlParameter(Types.VARCHAR));
compile();
}
}
```
```
@Test
public void testSqlUpdate() {
SqlUpdate insert = new InsertUserModel(jdbcTemplate);
insert.update("name5");
String updateSql = "update test set name=? where name=?";
SqlUpdate update = new SqlUpdate(jdbcTemplate.getDataSource(), updateSql, new int[]{Types.VARCHAR, Types.VARCHAR});
update.update("name6", "name5");
String deleteSql = "delete from test where name=:name";
SqlUpdate delete = new SqlUpdate(jdbcTemplate.getDataSource(), deleteSql, new int[]{Types.VARCHAR});
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("name", "name5");
delete.updateByNamedParam(paramMap);
}
```
InsertUserModel類實現類似于SqlQuery實現,用于執行數據庫插入操作,SqlUpdate還提供一種更簡潔的構造器SqlUpdate(DataSource ds, String sql, int[] types),其中types用于指定占位符或命名參數類型;SqlUpdate還支持命名參數,使用updateByNamedParam方法來進行命名參數操作。
### 7.3.4? 存儲過程及函數
StoredProcedure用于支持存儲過程及函數,該類的使用同樣類似于SqlQuery。
StoredProcedure提供execute方法用于執行存儲過程及函數。
**一、StoredProcedure如何調用自定義函數:**
```
@Test
public void testStoredProcedure1() {
StoredProcedure lengthFunction = new HsqldbLengthFunction(jdbcTemplate);
Map<String,Object> outValues = lengthFunction.execute("test");
Assert.assertEquals(4, outValues.get("result"));
}
```
StoredProcedure使用非常簡單,定義StoredProcedure實現HsqldbLengthFunction,并調用execute方法執行即可,接下來看一下HsqldbLengthFunction實現:
```
package cn.javass.spring.chapter7;
//省略import
public class HsqldbLengthFunction extends StoredProcedure {
public HsqldbLengthFunction(JdbcTemplate jdbcTemplate) {
super.setJdbcTemplate(jdbcTemplate);
super.setSql("FUNCTION_TEST");
super.declareParameter(
new SqlReturnResultSet("result", new ResultSetExtractor<Integer>() {
@Override
public Integer extractData(ResultSet rs) throws SQLException, DataAccessException {
while(rs.next()) {
return rs.getInt(1);
}
return 0;
}
}));
super.declareParameter(new SqlParameter("str", Types.VARCHAR));
compile();
}
}
```
StoredProcedure自定義函數使用類似于SqlQuery,首先設置數據源或JdbcTemplate對象,其次定義自定義函數,然后使用declareParameter進行參數描述,最后調用compile(可選)編譯自定義函數。
接下來看一下mysql自定義函數如何使用:
```
@Test
public void testStoredProcedure2() {
JdbcTemplate mysqlJdbcTemplate = new JdbcTemplate(getMysqlDataSource());
String createFunctionSql =
"CREATE FUNCTION FUNCTION_TEST(str VARCHAR(100)) " +
"returns INT return LENGTH(str)";
String dropFunctionSql = "DROP FUNCTION IF EXISTS FUNCTION_TEST";
mysqlJdbcTemplate.update(dropFunctionSql);
mysqlJdbcTemplate.update(createFunctionSql);
StoredProcedure lengthFunction = new MysqlLengthFunction(mysqlJdbcTemplate);
Map<String,Object> outValues = lengthFunction.execute("test");
Assert.assertEquals(4, outValues.get("result"));
}
```
MysqlLengthFunction自定義函數使用與HsqldbLengthFunction使用完全一樣,只是內部實現稍有差別:
```
package cn.javass.spring.chapter7;
//省略import
public class MysqlLengthFunction extends StoredProcedure {
public MysqlLengthFunction(JdbcTemplate jdbcTemplate) {
super.setJdbcTemplate(jdbcTemplate);
super.setSql("FUNCTION_TEST");
super.setFunction(true);
super.declareParameter(new SqlOutParameter("result", Types.INTEGER));
super.declareParameter(new SqlParameter("str", Types.VARCHAR));
compile();
}
}
```
MysqlLengthFunction與HsqldbLengthFunction實現不同的地方有兩點:
* **setFunction(true):**表示是自定義函數調用,即編譯后的sql為{?= call …}形式;如果使用hsqldb不能設置為true,因為在hsqldb中{?= call …}和{call …}含義一樣;
* **declareParameter(new SqlOutParameter("result", Types.INTEGER))**:將自定義函數返回值類型直接描述為Types.INTEGER;SqlOutParameter必須指定name,而不用使用SqlReturnResultSet首先獲取結果集,然后再從結果集獲取返回值,這是mysql與hsqldb的區別;
**一、StoredProcedure如何調用存儲過程:**
```
@Test
public void testStoredProcedure3() {
StoredProcedure procedure = new HsqldbTestProcedure(jdbcTemplate);
Map<String,Object> outValues = procedure.execute("test");
Assert.assertEquals(0, outValues.get("outId"));
Assert.assertEquals("Hello,test", outValues.get("inOutName"));
}
```
StoredProcedure存儲過程實現HsqldbTestProcedure調用與HsqldbLengthFunction調用完全一樣,不同的是在實現時,參數描述稍有不同:
```
package cn.javass.spring.chapter7;
//省略import
public class HsqldbTestProcedure extends StoredProcedure {
public HsqldbTestProcedure(JdbcTemplate jdbcTemplate) {
super.setJdbcTemplate(jdbcTemplate);
super.setSql("PROCEDURE_TEST");
super.declareParameter(new SqlInOutParameter("inOutName", Types.VARCHAR));
super.declareParameter(new SqlOutParameter("outId", Types.INTEGER));
compile();
}
}
```
* **declareParameter:**使用SqlInOutParameter描述INOUT類型參數,使用SqlOutParameter描述OUT類型參數,必須按順序定義,不能顛倒。
原創內容,轉載請注明出處【[http://sishuok.com/forum/blogPost/list/0/2491.html](http://sishuok.com/forum/blogPost/list/0/2491.html#7206)】
- 跟我學 Spring3
- 【第二章】 IoC 之 2.1 IoC基礎 ——跟我學Spring3
- 【第二章】 IoC 之 2.2 IoC 容器基本原理 ——跟我學Spring3
- 【第二章】 IoC 之 2.3 IoC的配置使用——跟我學Spring3
- 【第三章】 DI 之 3.1 DI的配置使用 ——跟我學spring3
- 【第三章】 DI 之 3.2 循環依賴 ——跟我學spring3
- 【第三章】 DI 之 3.3 更多DI的知識 ——跟我學spring3
- 【第三章】 DI 之 3.4 Bean的作用域 ——跟我學spring3
- 【第四章】 資源 之 4.1 基礎知識 ——跟我學spring3
- 【第四章】 資源 之 4.2 內置Resource實現 ——跟我學spring3
- 【第四章】 資源 之 4.3 訪問Resource ——跟我學spring3
- 【第四章】 資源 之 4.4 Resource通配符路徑 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.1 概述 5.2 SpEL基礎 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.3 SpEL語法 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.4在Bean定義中使用EL—跟我學spring3
- 【第六章】 AOP 之 6.1 AOP基礎 ——跟我學spring3
- 【第六章】 AOP 之 6.2 AOP的HelloWorld ——跟我學spring3
- 【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.5 AspectJ切入點語法詳解 ——跟我學spring3
- 【第六章】 AOP 之 6.6 通知參數 ——跟我學spring3
- 【第六章】 AOP 之 6.7 通知順序 ——跟我學spring3
- 【第六章】 AOP 之 6.8 切面實例化模型 ——跟我學spring3
- 【第六章】 AOP 之 6.9 代理機制 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.1 概述 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.2 JDBC模板類 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.3 關系數據庫操作對象化 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.4 Spring提供的其它幫助 ——跟我學spring3【私塾在線原創】
- 【第七章】 對JDBC的支持 之 7.5 集成Spring JDBC及最佳實踐 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.1 概述 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.2 集成Hibernate3 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.3 集成iBATIS ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.4 集成JPA ——跟我學spring3
- 【第九章】 Spring的事務 之 9.1 數據庫事務概述 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.2 事務管理器 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.3 編程式事務 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.4 聲明式事務 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.1 概述 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.2 集成Struts1.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.3 集成Struts2.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.4 集成JSF ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.1 概述 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.2 實現通用層 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.3 實現積分商城層 ——跟我學spring3
- 【第十二章】零配置 之 12.1 概述 ——跟我學spring3
- 【第十二章】零配置 之 12.2 注解實現Bean依賴注入 ——跟我學spring3
- 【第十二章】零配置 之 12.3 注解實現Bean定義 ——跟我學spring3
- 【第十二章】零配置 之 12.4 基于Java類定義Bean配置元數據 ——跟我學spring3
- 【第十二章】零配置 之 12.5 綜合示例-積分商城 ——跟我學spring3
- 【第十三章】 測試 之 13.1 概述 13.2 單元測試 ——跟我學spring3
- 【第十三章】 測試 之 13.3 集成測試 ——跟我學spring3
- 跟我學 Spring MVC
- SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常見問題總結
- Spring Web MVC中的頁面緩存支持 ——跟我學SpringMVC系列
- Spring3 Web MVC下的數據類型轉換(第一篇)——《跟我學Spring3 Web MVC》搶先看
- Spring3 Web MVC下的數據格式化(第二篇)——《跟我學Spring3 Web MVC》搶先看
- 第一章 Web MVC簡介 —— 跟開濤學SpringMVC
- 第二章 Spring MVC入門 —— 跟開濤學SpringMVC
- 第三章 DispatcherServlet詳解 ——跟開濤學SpringMVC
- 第四章 Controller接口控制器詳解(1)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(2)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(3)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解 (4)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(5)——跟著開濤學SpringMVC
- 跟著開濤學SpringMVC 第一章源代碼下載
- 第二章 Spring MVC入門 源代碼下載
- 第四章 Controller接口控制器詳解 源代碼下載
- 第四章 Controller接口控制器詳解(6)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(7 完)——跟著開濤學SpringMVC
- 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 源代碼下載 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 注解式控制器運行流程及處理器定義 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- 源代碼下載 第六章 注解式控制器詳解
- SpringMVC3強大的請求映射規則詳解 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- Spring MVC 3.1新特性 生產者、消費者請求限定 —— 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(1)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(2)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC數據類型轉換——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據格式化——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據驗證——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC