# 【第七章】 對JDBC的支持 之 7.4 Spring提供的其它幫助 ——跟我學spring3【私塾在線原創】
7.4? Spring提供的其它幫助
### 7.4.1??**SimpleJdbc方式**
Spring JDBC抽象框架提供SimpleJdbcInsert和SimpleJdbcCall類,這兩個類通過利用JDBC驅動提供的數據庫元數據來簡化JDBC操作。
1、SimpleJdbcInsert: 用于插入數據,根據數據庫元數據進行插入數據,本類用于簡化插入操作,提供三種類型方法:execute方法用于普通插入、executeAndReturnKey及executeAndReturnKeyHolder方法用于插入時獲取主鍵值、executeBatch方法用于批處理。
```
@Test
public void testSimpleJdbcInsert() {
SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate);
insert.withTableName("test");
Map<String, Object> args = new HashMap<String, Object>();
args.put("name", "name5");
insert.compile();
//1.普通插入
insert.execute(args);
Assert.assertEquals(1, jdbcTemplate.queryForInt("select count(*) from test"));
//2.插入時獲取主鍵值
insert = new SimpleJdbcInsert(jdbcTemplate);
insert.withTableName("test");
insert.setGeneratedKeyName("id");
Number id = insert.executeAndReturnKey(args);
Assert.assertEquals(1, id);
//3.批處理
insert = new SimpleJdbcInsert(jdbcTemplate);
insert.withTableName("test");
insert.setGeneratedKeyName("id");
int[] updateCount = insert.executeBatch(new Map[] {args, args, args});
Assert.assertEquals(1, updateCount[0]);
Assert.assertEquals(5, jdbcTemplate.queryForInt("select count(*) from test"));
}
```
* **new SimpleJdbcInsert(jdbcTemplate)** **:** 首次通過DataSource對象或JdbcTemplate對象初始化SimpleJdbcInsert;
* **insert.withTableName("test")** **:** 用于設置數據庫表名;
* **args** **:** 用于指定插入時列名及值,如本例中只有name列名,即編譯后的sql類似于“insert into test(name) values(?)”;
* **insert.compile()** **:** 可選的編譯步驟,在調用執行方法時自動編譯,編譯后不能再對insert對象修改;
* **執行:** execute方法用于執行普通插入;executeAndReturnKey用于執行并獲取自動生成主鍵(注意是Number類型),必須首先通過setGeneratedKeyName設置主鍵然后才能獲取,如果想獲取復合主鍵請使用setGeneratedKeyNames描述主鍵然后通過executeReturningKeyHolder獲取復合主鍵KeyHolder對象;executeBatch用于批處理;
2、SimpleJdbcCall: 用于調用存儲過程及自定義函數,本類用于簡化存儲過程及自定義函數調用。
```
@Test
public void testSimpleJdbcCall1() {
//此處用mysql,因為hsqldb調用自定義函數和存儲過程一樣
SimpleJdbcCall call = new SimpleJdbcCall(getMysqlDataSource());
call.withFunctionName("FUNCTION_TEST");
call.declareParameters(new SqlOutParameter("result", Types.INTEGER));
call.declareParameters(new SqlParameter("str", Types.VARCHAR));
Map<String, Object> outVlaues = call.execute("test");
Assert.assertEquals(4, outVlaues.get("result"));
}
```
* **new SimpleJdbcCall(getMysqlDataSource())** :通過DataSource對象或JdbcTemplate對象初始化SimpleJdbcCall;
* **withFunctionName("FUNCTION_TEST")** **:** 定義自定義函數名;自定義函數sql語句將被編譯為類似于{?= call …}形式;
* **declareParameters** **:** 描述參數類型,使用方式與StoredProcedure對象一樣;
* **執行:** 調用execute方法執行自定義函數;
```
@Test
public void testSimpleJdbcCall2() {
//調用hsqldb自定義函數得使用如下方式
SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate);
call.withProcedureName("FUNCTION_TEST");
call.declareParameters(new SqlReturnResultSet("result",
new ResultSetExtractor<Integer>() {
@Override
public Integer extractData(ResultSet rs)
throws SQLException, DataAccessException {
while(rs.next()) {
return rs.getInt(1);
}
return 0;
}}));
call.declareParameters(new SqlParameter("str", Types.VARCHAR));
Map<String, Object> outVlaues = call.execute("test");
Assert.assertEquals(4, outVlaues.get("result"));
}
```
調用hsqldb數據庫自定義函數與調用mysql自定義函數完全不同,詳見StoredProcedure中的解釋。
```
@Test
public void testSimpleJdbcCall3() {
SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate);
call.withProcedureName("PROCEDURE_TEST");
call.declareParameters(new SqlInOutParameter("inOutName", Types.VARCHAR));
call.declareParameters(new SqlOutParameter("outId", Types.INTEGER));
SqlParameterSource params =
new MapSqlParameterSource().addValue("inOutName", "test");
Map<String, Object> outVlaues = call.execute(params);
Assert.assertEquals("Hello,test", outVlaues.get("inOutName"));
Assert.assertEquals(0, outVlaues.get("outId"));
}
```
與自定義函數調用不同的是使用withProcedureName來指定存儲過程名字;其他參數描述等完全一樣。
### 7.4.2? 控制數據庫連接
Spring JDBC通過DataSource控制數據庫連接,即通過DataSource實現獲取數據庫連接。
Spring JDBC提供了一下DataSource實現:
* **DriverManagerDataSource** :簡單封裝了DriverManager獲取數據庫連接;通過DriverManager的getConnection方法獲取數據庫連接;
* **SingleConnectionDataSource** :內部封裝了一個連接,該連接使用后不會關閉,且不能在多線程環境中使用,一般用于測試;
* **LazyConnectionDataSourceProxy** :包裝一個DataSource,用于延遲獲取數據庫連接,只有在真正創建Statement等時才獲取連接,因此再說實際項目中最后使用該代理包裝原始DataSource從而使得只有在真正需要連接時才去獲取。
第三方提供的DataSource實現主要有C3P0、Proxool、DBCP等,這些實現都具有數據庫連接池能力。
**DataSourceUtils:** Spring JDBC抽象框架內部都是通過它的getConnection(DataSource dataSource)方法獲取數據庫連接,releaseConnection(Connection con, DataSource dataSource) 用于釋放數據庫連接,DataSourceUtils用于支持Spring管理事務,只有使用DataSourceUtils獲取的連接才具有Spring管理事務。
### 7.4.3? 獲取自動生成的主鍵
有許多數據庫提供自動生成主鍵的能力,因此我們可能需要獲取這些自動生成的主鍵,JDBC 3.0標準支持獲取自動生成的主鍵,且必須數據庫支持自動生成鍵獲取。
**1** **)JdbcTemplate** **獲取自動生成主鍵方式:**
```
@Test
public void testFetchKey1() throws SQLException {
final String insertSql = "insert into test(name) values('name5')";
KeyHolder generatedKeyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection conn)
throws SQLException {
return conn.prepareStatement(insertSql, new String[]{"ID"});
}}, generatedKeyHolder);
Assert.assertEquals(0, generatedKeyHolder.getKey());
}
```
使用JdbcTemplate的update(final PreparedStatementCreator psc, final KeyHolder generatedKeyHolder)方法執行需要返回自動生成主鍵的插入語句,其中psc用于創建PreparedStatement并指定自動生成鍵,如“prepareStatement(insertSql, new String[]{"ID"})”;generatedKeyHolder是KeyHolder類型,用于獲取自動生成的主鍵或復合主鍵;如使用getKey方法獲取自動生成的主鍵。
**2** **)SqlUpdate** **獲取自動生成主鍵方式:**
```
@Test
public void testFetchKey2() {
final String insertSql = "insert into test(name) values('name5')";
KeyHolder generatedKeyHolder = new GeneratedKeyHolder();
SqlUpdate update = new SqlUpdate();
update.setJdbcTemplate(jdbcTemplate);
update.setReturnGeneratedKeys(true);
//update.setGeneratedKeysColumnNames(new String[]{"ID"});
update.setSql(insertSql);
update.update(null, generatedKeyHolder);
Assert.assertEquals(0, generatedKeyHolder.getKey());
}
```
SqlUpdate獲取自動生成主鍵方式和JdbcTemplate完全一樣,可以使用setReturnGeneratedKeys(true)表示要獲取自動生成鍵;也可以使用setGeneratedKeysColumnNames指定自動生成鍵列名。
**3** **)SimpleJdbcInsert** **:** 前邊示例已介紹,此處就不演示了。
### 7.4.4? JDBC批量操作
JDBC批處理用于減少與數據庫交互的次數來提升性能,Spring JDBC抽象框架通過封裝批處理操作來簡化批處理操作
**1** **)JdbcTemplate** **批處理:** 支持普通的批處理及占位符批處理;
```
@Test
public void testBatchUpdate1() {
String insertSql = "insert into test(name) values('name5')";
String[] batchSql = new String[] {insertSql, insertSql};
jdbcTemplate.batchUpdate(batchSql);
Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));
}
```
直接調用batchUpdate方法執行需要批處理的語句即可。
```
@Test
public void testBatchUpdate2() {
String insertSql = "insert into test(name) values(?)";
final String[] batchValues = new String[] {"name5", "name6"};
jdbcTemplate.batchUpdate(insertSql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, batchValues[i]);
}
@Override
public int getBatchSize() {
return batchValues.length;
}
});
Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));
}
```
JdbcTemplate還可以通過batchUpdate(String sql, final BatchPreparedStatementSetter pss)方法進行批處理,該方式使用預編譯語句,然后通過BatchPreparedStatementSetter實現進行設值(setValues)及指定批處理大小(getBatchSize)。
**2** **)NamedParameterJdbcTemplate** **批處理:** 支持命名參數批處理;
```
@Test
public void testBatchUpdate3() {
NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
String insertSql = "insert into test(name) values(:myName)";
UserModel model = new UserModel();
model.setMyName("name5");
SqlParameterSource[] params = SqlParameterSourceUtils.createBatch(new Object[] {model, model});
namedParameterJdbcTemplate.batchUpdate(insertSql, params);
Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));
}
```
通過batchUpdate(String sql, SqlParameterSource[] batchArgs)方法進行命名參數批處理,batchArgs指定批處理數據集。SqlParameterSourceUtils.createBatch用于根據JavaBean對象或者Map創建相應的BeanPropertySqlParameterSource或MapSqlParameterSource。
**3) SimpleJdbcTemplate** **批處理:** 已更簡單的方式進行批處理;
```
@Test
public void testBatchUpdate4() {
SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(jdbcTemplate);
String insertSql = "insert into test(name) values(?)";
List<Object[]> params = new ArrayList<Object[]>();
params.add(new Object[]{"name5"});
params.add(new Object[]{"name5"});
simpleJdbcTemplate.batchUpdate(insertSql, params);
Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));
}
```
本示例使用batchUpdate(String sql, List<Object[]> batchArgs)方法完成占位符批處理,當然也支持命名參數批處理等。
**4** **)SimpleJdbcInsert** **批處理:**
```
@Test
public void testBatchUpdate5() {
SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate);
insert.withTableName("test");
Map<String, Object> valueMap = new HashMap<String, Object>();
valueMap.put("name", "name5");
insert.executeBatch(new Map[] {valueMap, valueMap});
Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));
}
```
如代碼所示,使用executeBatch(Map<String, Object>[] batch)方法執行批處理。? ? ? ?
- 跟我學 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