Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Spring 2.0 技術手冊第五章 - JDBC、交易支援

4,703 views

Published on

Spring 2.0 技術手冊

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Spring 2.0 技術手冊第五章 - JDBC、交易支援

  1. 1. 。援支些一的上易交及以取存 JDBC 於 紹介來子例的際實些一以將,中節 Spring章 個 這 在。能 功 的 務 服 關 相 等 易 交 得 獲 易 輕 並,式 方 用 運 的 化 JDBC簡 以 可,能 功 的 供 提 所 架 框 與 器 容 AOP 合 結,之 言 而 總 Spring IoC 。) ( D eclarative transaction management理管易交式告宣與) ( P rogrammatic transaction management理管易交式程編了供提 ,面方理處的易交於關。用使 Spring作操的上 在 API JDBC 化簡以別類等 了供提也 JdbcTemplate Spring,上用使的 JDBC API 在。外例的定特理處否是擇選以可您,裝封新重以加 外例些一 的時取 存庫料資對 。節細術技的庫料資層底 S pring觸 接 用 不 以 可 您 ,架 框 了 供 提 DAO ,援 支 的 取 存 庫 料 資 於 對 S pring JDBC、交易支援 5
  2. 2. 2 } public void delete(User user); public void update(User user); public User find(Integer id); public void insert(User user); public interface IUserDAO { package onlyfun.caterpillar; :面介 IUserDAO 個 一 如例, 面 介 個 一 賴 依 它 讓以可 而 , 作 實 別 類 的 際實個一於賴依應不式程用應,) 、 、 、 如例(時取 d elete u pdate i nsert select User存 庫 料 資 行 進 在, 件 物 個 有 中 式 程 用 應 設 假, 子 例 的 個 舉 DAO 。節細關相的時取存作實,中之法方的範規在並,面介該作實要件物的取存庫料資行進上際實而,作操來面介取存料資個一過透是,時取存料資到用使要需,中式程用應在, Data Access Object D AO 為 名 全 的 ,節 細 術 技 庫 料 資 定 特的用 使 所 到 觸 接 須 無 ,時取 存 庫 料 資 行 進 在 您 讓 架 框 的 DAO Spring 5.1.1 Spring 的 DAO 支持 。層久持 Spring門入來子例的際實以並,計 設 DAO 的 Spring 介簡來先節小個這,術技庫料 資 定 特 於 合 耦 須 無時發 開 式 程 用 應 讓 , 架 框 了供提 DAO Spring 5.1 Spring 持久層入門 ) – http://openhome.cc 良信林(冊手術技 Spring 2.0
  3. 3. Chapter 5 JDBC 援支易交、作 實 以 可 別 類 的取存 庫 料 資 行 進 上 際 實 IUserDAO 一義定如例,面介 :別類 UserDAO 的單簡個package onlyfun.caterpillar;...public class UserDAO implements IUserDAO { private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public void insert(User user) { String name = user.getName(); int age = user.getAge().intValue(); Connection conn = null; PreparedStatement stmt = null; try { conn = dataSource.getConnection(); stmt = conn.prepareStatement ( "INSERT INTO user (name,age) VALUES(?,?)"); stmt.setString(1, name); stmt.setInt(2, age); stmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { if(stmt != null) { try { stmt.close(); } catch(SQLException e) { e.printStackTrace(); } } if(conn != null) { try { conn.close(); } 3
  4. 4. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) catch(SQLException e) { e.printStackTrace(); } } } } public User find(Integer id) { ... return user; } public void update(User user) { ... } public void delete(User user) { ... }}用 使以可 , 時 取 存 料 資 行 進在程 流 主 式 程 用 應 的 您 IUserDAO 告宣來 :如例,面介作操...User user = new User();user.setName("caterpillar");user.setAge(new Integer(30));IUserDAO userDao = getUserDAO();userDao.insert(user);...而,別類作實的 換替時隨以可以所,面介於賴依於由 IUserDAO術技的取存庫料資層底與何任有沒並,上法方作操的告宣面介IUserDAO層 底與式 程 用 應 將 , 理 原 本基的 樣 這 於 基 是 正 架 框 S pring DAO 的 ,節細 :來開離隔術技取存4
  5. 5. Chapter 5 JDBC 援支易交、 圖 5.1 DAO 圖意示作運如例(法方的關無術技取存庫料資定特與有只上面介取存料資不 也,試 測 於 易 也 式 程 , 面介於 賴 依 上 計 設 , ) 等update i nsert d elete 、 、 。術 技 庫 料 資 一 某 用 使能只 於 限 受 式 程 用 應 讓驟步個幾有,說來程流取存庫料資的際實於對,中式程範示的前之在不 於 對, 等 外 例 理 處、 得 取、 DataSource 得 取 如 例, 的 定 固 是 Connection設就,同不程流份部少有只,的同相是上致大驟步些這,術技庫料資的同於寫撰程流的定固將,式模 用使以可,言而上計 Template-Callback來件物Template 由委則,驟步節細些一的同不於對而,中之別類 Callback有中其於對,程流的定固是份部字體粗非,中段片式程的下以如例,成完 :件物 的 當 適 回 傳 或 行 執 來 件 物 的 別 個作實 以 可 , 份 部 的 異 差 Callback ... Connection conn = null; PreparedStatement stmt = null; try { conn = dataSource.getConnection(); stmt = callback.createPreparedStatement(conn); stmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { if(stmtCallback != null) { try { stmt.close(); }
  6. 6. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) catch(SQLException e) { e.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch(SQLException e) { e.printStackTrace(); } } }於寫撰程流的定固將,式模 Spring 了用運就 Template-Callback而,)別類Template 、 如例(中之別類 JdbcTemplate H ibernateTemplate定 自以可 ( 理 處 來 件 物 援 支 定 特 託 委 則 , 驟步節 細 些 一 的 同 不 於 對 DAO Spring :)生產動自 由或義 圖 5.2 DAO Template 與 DAO Support應讓,系體理處外例的關無術技定特與供提也 ,面方理處外例在 S pring,) 、 是像( 外例定特 理處因會不式 程用 SQLException H ibernateException 。術技層 久持或庫 料資種某於合 耦而6
  7. 7. 7 類子的 org.springframework.dao.DataAccessException 是都外例的 有所 S pring , 外 例 的 關相術 技 庫 料 資 與 出 丟 不 並 架 框 的 DAO Spring 。 續 手 的 道 多更要 就 , 層 上 至 出 丟 外例些 這 讓 要 想 果 如 , 掉 理處自暗來 try..catch 些一寫撰行自能只, 之將法無就,) throw Hibernate 是或 JDBC是像,況情種這有而同不術技層底的用使於由能可( 外例的明聲上法方是不些某了生發中法方些這在果如而然,外例的型類些 某 throws 明聲上法方於,時面介義定在會也們它,息訊外例的關相些一括 包,別類外例的關相承繼行自會架框或式程些有,面方一另,意主的好個 一是不也播傳層上向以可外例讓,外例告宣上法方在 用使接直 throws 。 外 例些這 掉 理 處 來 法 語 理 處 外例些一寫撰的何奈可莫好只員人計設式程,理處要定一求要器譯編於由 ,Checked exception 對 面 而然, ) ? 息 訊 的 線 連 法無下 錄 記 如 例 ( 理 處 的 力為能無些一作,中式程取存庫料資的層底在是不而,邊哪在出題問知得 者用使讓,息訊關相示顯以捉捕式程用應層上由,式程用應層上至播傳外 例讓,理處不是就式方理處的好最,)線連得取法無如例(時生發取存庫 料資的層底在外例的類這當,作運常正至復回力無往往 Checked exception 於對,候時有而然,作運常正復回能式程至理處以加以可員人計設式程是 的 望 希, 時 生 發 外 例 類 這 於 對, 的 好 是 來 本 意 立 的 Checked exception 。)面 介 形 圖 者 用 使 如 例(理 處 層 上 最 式 程 用 應至出 丟 接 直 外 例 讓 是 或 ,理處作來 try...catch 用使擇選以可,時生發的真外例,外例的發引所期時 行 執 在 ,誤 錯 的 上 輯 邏 式 程 於 由 是 常 通 , 別 類 子 的 別 類 RuntimeException java.lang. 是上構架承繼外例在,) Runtime exception (外例期時 行執是則 U nckecked exception ;理處以加 try...catch 以上法語在須必此因 ,理處要定一求要器譯編,的生發期預以可是常通外例些這為因,外例的 理 處須必 上 法 語 在 期 時 譯 編 是 C hecked exception 。 Unchecked exception 與 Checked exception 有外例的 ,理處外例解瞭來先首 Java 援支易交、 Chapter 5 JDBC
  8. 8. 8取來 org.springframework.jdbc.datasource.DriverManagerDataSource供提 Spring ,面介作操的入注 Datasource 個一留保上件物 Bean的源來接連得取要需在以可,此為,輯邏務商的層上到響影應不為行些這,為行的層底是動更的源來料資,等 過透是或、池接連過透、 用 JNDI JDBC使的綷純如例,源來料資的同不用使能可式程用應,統系的同不應因 。式程行一 何任改 修 用 不 而 , 置 配 改 修 中 檔 義 定 Bean 在 要只源 來 料 資 換 更 , 入 注javax.sql.DataSource 了供提 S pring ,求需源來接連料資的同不於對 5.1.2 DataSource 注入 。圖承繼別類的 DataAccessException 個有也,明說的理處外例對些一有中當,節章 DAO support 的中件文考參 看看以可。捉 Spring捕 以加外 例 的 理 處 想 對 針 以 可 您 , 等 BadSqlGrammarException 的時誤錯法語 、 S QL DataAccessResourceFailureException 的出丟會時誤錯結連庫 料 資 如 例 , 類 分 了 好 作 外 例 將 也 S pring ,外例 的 定 特 理 處 要 果 如 JVM 。 理 處 來 由 後 最 是 或 式程用 應 的 層 上 最 由 , 它略 忽 者 或 ,它 理 處 擇 選 以 可 您 , 外 例 些 一 於 對 , RuntimeException 自承繼NestedRuntimeException 而, NestedRuntimeException 的件套 work.coreorg.springframe- 自 承 繼 它,別 類 礎 基 的 次 層 個 這 是 DataAccessException,次層理處外例的性致一供提下件套 o rg.springframework.dao ,件物 DAO外例 的己自為化轉等 SQLException 將 ,取存 S pring 於對 JDBC。 式程用 應 的 層 上 至 播 傳 外例將 的 單 簡 很 以 可 也 ,下況 情 的 外 例 理 處 不 在,理處 要 不 要 擇 選 己 自 以 可 而 , 外 例 理 處 來 try...catch 用使迫強被用不您,Unchecked exception 於屬是 它 說 是 就 也 , 別 類 子 的 RuntimeException是 DataAccessException 且而,外例用通的關無術技庫料資與個一,別 ) – http://openhome.cc 良信林(冊手術技 Spring 2.0
  9. 9. Chapter 5 JDBC 援支易交、 ,例實的它得 D riverManagerDataSource 了作實 javax.sql.DataSource 您,:寫撰麼這中檔義定 在以可 Bean...<beans...> <bean id="dataSource" class="org.springframework.jdbc. → datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/demo"/> <property name="username" value="caterpillar"/> <property name="password" value="123456"/> </bean> ...</beans> 屬個四 "driverClassName" 、 " url"中其、 、 " username" " password" JDBC 定設來用是別分性 、稱名者用使、定協 庫料資、別類式程動驅 URL 。碼密前之範示並,範示的入注 為 作 來 式程個 一 用 使 際 實 邊 這 在DataSource :下如面介作操的 個一了義定您設假,作實的紹介 於關有 DAO DAO DataSourceDemo IUserDAO.javapackage onlyfun.caterpillar;public interface IUserDAO { public void insert(User user); public User find(Integer id);} 有 只 義 定 面 介 的 於 關 邊 這,制 限 的 幅 篇 於 基 DAO insert() 與 find() 兩: 義 定 下 如 則 別 類 的 到 用 使 所中面 介 個 這 在 。 法 方 個 User
  10. 10. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) DataSourceDemo User.java package onlyfun.caterpillar; public class User { private Integer id; private String name; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }了作實它,別類 個一義定以可著接 UserDAO IUserDAO 實是,面介 : 示 所 下 如 , 件 物 的務服 取 存 庫 料 資 行 進 際1
  11. 11. Chapter 5 JDBC 援支易交、 DataSourceDemo UserDAO.javapackage onlyfun.caterpillar;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import javax.sql.DataSource;public class UserDAO implements IUserDAO { private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public void insert(User user) { String name = user.getName(); int age = user.getAge().intValue(); Connection conn = null; PreparedStatement stmt = null; try { conn = dataSource.getConnection(); stmt = conn.prepareStatement ( "INSERT INTO user (name,age) VALUES(?,?)"); stmt.setString(1, name); stmt.setInt(2, age); stmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { if(stmt != null) { try { stmt.close(); } catch(SQLException e) { e.printStackTrace(); } } 11
  12. 12. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) if(conn != null) { try { conn.close(); } catch(SQLException e) { e.printStackTrace(); } } } } public User find(Integer id) { Connection conn = null; PreparedStatement stmt = null; try { conn = dataSource.getConnection(); stmt = conn.prepareStatement( "SELECT * FROM user WHERE id=?"); stmt.setInt(1, id.intValue()); ResultSet result = stmt.executeQuery(); if(result.next()) { Integer i = new Integer(result.getInt(1)); String name = result.getString(2); Integer age = new Integer(result.getInt(3)); User user = new User(); user.setId(i); user.setName(name); user.setAge(age); return user; } } catch (SQLException e) { e.printStackTrace(); } finally { if(stmt != null) { try { stmt.close(); }12
  13. 13. Chapter 5 JDBC 援支易交、 catch(SQLException e) { e.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch(SQLException e) { e.printStackTrace(); } } } return null; }} UserDAO 入注您讓以可,法方 個一告宣上別類 setDataSource()DataSource :示所下如,義定的入注賴依行進中檔義定 在以可,例實的 Bean DataSourceDemo beans-config.xml<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="dataSource" class="org.springframework.jdbc. → datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/demo"/> <property name="username" value="caterpillar"/> <property name="password" value="123456"/> </bean> 13
  14. 14. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) <bean id="userDAO" class="onlyfun.caterpillar.UserDAO"> <property name="dataSource" ref="dataSource"/> </bean> </beans>作 操 來 式 程 試測的 單 簡 個 一 寫 撰 以 可 UserDAO 能否是看看,例實的 :詢查 與 存 儲 的 料 資 行 進 DataSourceDemo SpringDAODemo.java package onlyfun.caterpillar; import org.springframework.context.ApplicationContext; import org.springframework.context. support.ClassPathXmlApplicationContext; public class SpringDAODemo { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( "beans-config.xml"); User user = new User(); user.setName("caterpillar"); user.setAge(new Integer(30)); IUserDAO userDAO = (IUserDAO) context.getBean("userDAO"); userDAO.insert(user); user = userDAO.find(new Integer(1)); System.out.println("name: " + user.getName()); } }14
  15. 15. Chapter 5 JDBC 援支易交、 將並,務服庫料資啟開先要您,前之試測的式程行進在 beans- 與 稱 名 者 用 使、 庫 料 資、別 類 式 程 動 驅 的 關 相 中 config.xml URL 而,庫 料 資 是 的 用 使 所 邊 這 在,定 設 的 您 為 改 修 等 碼 密 MySQL user :的立建來 的下以用使是格表 的立建 SQL CREATE TABLE user ( id INT(11) NOT NULL auto_increment PRIMARY KEY, name VARCHAR(100) NOT NULL default , age INT ); 據根著接,料資筆一入存中格表 的庫料資在先會果結行執的式程 userid 。字文的 示顯會果結後最,料資的入存所前先出詢查值 "name: caterpillar" 、 、 spring-core.jar 、 要需您 s pring-beans.jar s pring-context.jar spring-dao.jar spring-jdbc.jar 是 的 用 使 您 果 如,案 檔 個 幾 這 與 的依相要需也外另, 關相了括包經已中當, spring.jar API 有 要 須 必 您, 用 使 了 為,然 當, commons-logging.jar JDBC JDBC jar 。案檔 的式程動驅5.1.3 DataSource 置換單簡作來用是只,能功的池接連供提有沒並 DriverManagerDataSource以 用 使 以 可 您。中 之 案 專 的 正 真 於 用 使 合 適 不 並,試 測 接 連 機 單 的 DBCP程改修要需不並 換置則, 用使果如。能功的池接連得獲 Spring DataSource 下一改修如例,了以可就檔義定 改修要只,碼始原式 Bean DataSourceDemo beans-config.xml :下如 的中案專 1
  16. 16. Spring 2.0 良信林(冊手術技 – http://openhome.cc )<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/demo"/> <property name="username" value="caterpillar"/> <property name="password" value="123456"/> </bean> <bean id="userDAO" class="onlyfun.caterpillar.UserDAO"> <property name="dataSource" ref="dataSource"/> </bean></beans> 是的用使所在現 org.apache.commons.dbcp.BasicDataSource 作 在要需您,能功的 用使了為,例實 DataSource 的入注為 DBCP Classpath 與 、 定設中徑路 commons-dbcp.jar c ommons-pool.jar commonscollec- 。到找下錄目 的中本版依相的tions.jar 在以可都些這, Spring lib 確以可此如,性屬 了定設上 dataSource在到意注 "destroy-method" 。 BeanFactory 閉關併一也時閉關在 保 BasicDataSource) ( 了供提器容 Servlet 果如 JNDI J ava Naming and Directory Interface : DataSource個這上換的單簡以可也, 的 DataSource16
  17. 17. Chapter 5 JDBC 援支易交、...<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="jdbc/demo"/></bean>... 用使了為 org.springframework.indi.JndiObjectFactoryBean 需您, 要 , spring-context.jar " jndiName" 的定設所據根要上際實 JNDI ,稱名詢查在如例 Tomcat 於以可中 server.xml :定設麼這...<!—- 是錄目式程用應設假 JSP --><Context path="/JSP" docBase="JSP"> <!-- 是稱名庫料資用使 GUESTBOOK --> <Resource name="jdbc/demo" scope="Shareable" type="javax.sql.DataSource"/> <ResourceParams name="jdbc/demo"> <parameter> <name>factory</name> <value> org.apache.commons.dbcp.BasicDataSourceFactory </value> </parameter> <!-- DBCP database connection settings --> <!-- JDBC URL --> <parameter> <name>url</name> <value>jdbc:mysql://localhost/demo</value> </parameter> <!-- JDBC 式程動驅 --> <parameter> <name>driverClassName</name> <value>com.mysql.jdbc.Driver</value> </parameter> <!-- 碼密與者用使庫料資 --> <parameter> <name>username</name> <value>caterpillar</value> 17
  18. 18. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) </parameter> <parameter> <name>password</name> <value>123456</value> </parameter> <!-- DBCP connection pooling options --> <!-- 待等 Connection 制限不表 , 位單,間時的ms -1 --> <parameter> <name>maxWait</name> <value>3000</value> </parameter> <!-- 可多最中池接連 idle ,數 Connection 的 的少最是就也 Connection 制限不表 ,數0 --> <parameter> <name>maxIdle</name> <value>10</value> </parameter> <!-- 的多至池接連 Connection 0 制限不示表 ,數 --> <parameter> <name>maxActive</name> <value>100</value> </parameter> </ResourceParams></Context>...18
  19. 19. Chapter 5 JDBC 援支易交、5.2 JDBC 支援用使在 JDBC 如例,節細的瑣繁理處要是總,時 、 Connection S tatement 、得獲的 、 S QLException 、理處的 C onnection S tatement ,題問等閉關的 在Spring JDBC 化簡以可,別類個幾了供提上用使的 JDBC 。程流的時用使5.2.1 使用 JdbcTemplate使接直中 ,中案專 的紹 介 中 節 小 個 一 前 在 DataSourceDemo U serDAO、得取的 JDBC 理處要中當,法方 insert() find()與 作實來 用 Connection,等 閉關的Statement 、閉關的 、理處的外例、立建的 S tatement C onnection這 作須必 都 次 一 每 , 的 異 小同大 是 程 流 些 這 , 取 存 JDBC 的本基個一於對 。煩厭 人 令 實 著 程 流 的 樣類 Spring 了供提 org.springframework.jdbc.core.JdbcTemplate法 方作操 些 一 的 供 提 所 中 當 , ) ( 全 安緒行 執 為 計 設 被 它 , 別 T hread-safe可別類 的中案專 如例,程流的上以似類了裝封 DataSourceDemo UserDAO須必,例實的 立建要,寫改來 JdbcTemplate 用使的單簡以 JdbcTemplate :件 物 的 時 構 建 為 作 件 物 DataSource 個一有要JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);到看以可,作實容內的 中案專 DataSourceDemo 下一寫改來UserDAO : 進 改 的 樣 麼 什 有會上 程 流 寫 撰 的 式 程 在 , 時 JdbcTemplate 用使 1
  20. 20. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) JdbcTemplateDemo UserDAO.java package onlyfun.caterpillar; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate; public class UserDAO implements IUserDAO { private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); } public void insert(User user) { String name = user.getName(); int age = user.getAge().intValue(); jdbcTemplate.update("INSERT INTO user (name,age) " + "VALUES(" + name + "," + age + ")"); } public User find(Integer id) { List rows = jdbcTemplate.queryForList( "SELECT * FROM user WHERE id=" + id.intValue()); Iterator it = rows.iterator(); if(it.hasNext()) { Map userMap = (Map) it.next(); Integer i = new Integer(userMap.get("id").toString()); String name = userMap.get("name").toString(); Integer age = new Integer(userMap.get("age").toString()); User user = new User(); user.setId(i); user.setName(name); user.setAge(age);2
  21. 21. Chapter 5 JDBC 援支易交、 return user; } return null; }},動變用不都檔定設與式程的它其,了以可就 寫改要只 UserDAOSpring 由藉是要主,的示所稱名其如一 JdbcTemplate 的 Template Method 。裝封程流理處的 JDBC 現實來式模 用使果如 Hibernate) ( 的類之 ORM O bject-Relational Mapping 則,具 工 find() 一進以可還換轉的型模式聯關與型模件物中法方 。化簡的步了除,用使來 Spring 於立獨以可上本基能功等裝封 JDBC 的 Spring對是像,別類JdbcTemplate 的它其了供提還S pring ,外之 Template, 面方理 處 易 交 的 庫 料 資 在 。 現 實Hibernate J DO i Batis 的等 、 、 Template雜 複的式 程 層 久 持 了 化 簡 ,能功 理 管 易 交 的 式 告 宣 與 式 程 編 了 供 提Spring 。 性 護維的 好 更 了 供 提 並 , 度5.2.2 JdbcTemplate 執行與更新 用使以可您 JdbcTemplate 的 execute() 行執法方 SQL :如例,述陳jdbcTemplate.execute( "CREATE TABLE USER (user_id integer, name varchar(100))");是果如 用使以可您, UPDATE 或 INSERT update() 重個數有它,法方 (載 Overload 作實受接如例,本版) org.springframework.jdbc. 21
  22. 22. Spring 2.0 良信林(冊手術技 – http://openhome.cc )core.PreparedStatementCreator ,件物的面介 P reparedStatementCreator 介:下如義定的面package org.springframework.jdbc.core;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;public interface PreparedStatementCreator { PreparedStatement createPreparedStatement(Connection con) throws SQLException;}將以可如例 5.2.1 的 JdbcTemplateDemo 中案專 UserDAO 的 insert() 方 :下如寫改法...public void insert(User user) { final String name = user.getName(); final int age = user.getAge().intValue(); jdbcTemplate.update( new PreparedStatementCreator() { public PreparedStatement createPreparedStatement( Connection con) throws SQLException { String sql = "INSERT INTO user (name,age) VALUES(?,?)"; PreparedStatement ps = con.prepareStatement(sql); ps.setString(1, name); ps.setInt(2, age); return ps; } });}...22
  23. 23. Chapter 5 JDBC 援支易交、 備準 來 了用 使,中子例個 這在 PreparedStatement SQL , J dbcTemplate而,程流 了現實中法 方 ,制機 Template-Callback 了現實 u pdate() Template,中程流的 行執在,件物PreparedStatementCreator了現 實則 Callback JDBC方 是就也, 法 方 的義 定所行執會時 要必 callback createPreparedStatement() 的中 法 方 成完以,件 物 PreparedStatement 個一回傳 ,法 update() Template 。 程流 是面介的補互 PreparedStatementCreator 與 org.springframework.jdbc. :面介core.PreparedStatementSetterpackage org.springframework.jdbc.core;import java.sql.PreparedStatement;import java.sql.SQLException;public interface PreparedStatementSetter { void setValues(PreparedStatement ps) throws SQLException;} 將以可如例 JdbcTemplateDemo 中案專 UserDAO 的 insert() :下如寫改法方...public void insert(User user) { final String name = user.getName(); final int age = user.getAge().intValue(); jdbcTemplate.update( "INSERT INTO user (name,age) VALUES(?,?)", new PreparedStatementSetter() { public void setValues(PreparedStatement ps) throws SQLException { ps.setString(1, name); ps.setInt(2, age); } });}... 23
  24. 24. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) 立建動自會JdbcTemplate PreparedStatementCreator 供提以,例實的 的法方 給遞傳 setValues() PreparedStatement 。件物如就, 供提接直以可也您 SQL JdbcTemplateDemo 的範示所中案專 :法方UserDAO 的中 insert()...public void insert(User user) { String name = user.getName(); int age = user.getAge().intValue(); jdbcTemplate.update("INSERT INTO user (name,age) " + "VALUES(" + name + "," + age + ")");}...陣 件 物 用 使 並, 元 字 位 佔 為 作 用 使 以 可 也 , 時 句 語 下 接 直 在 SQL "?" 寫改如例,法方 的 JdbcTemplate 給遞 傳 數 引 為 作 列 update() JdbcTemplate-Demo :法方 的中 UserDAO 的範示所中案專 insert()...public void insert(User user) { jdbcTemplate.update( "INSERT INTO user (name, age) VALUES(?,?)", new Object[] {user.getName(), user.getAge()});}... JdbcTemplate 與 立建動自會 PreparedStatementCreator Prepared-StatementSetter 數引與 供提要只,會理用不您節細些這而然,例實的 SQL 。了好就作實以可,時理處次批要需果如 org.springframework.jdbc.core.Batch- :面介PreparedStatementSetter24
  25. 25. Chapter 5 JDBC 援支易交、package org.springframework.jdbc.core;import java.sql.PreparedStatement;import java.sql.SQLException;public interface BatchPreparedStatementSetter { void setValues(PreparedStatement ps, int i) throws SQLException; int getBatchSize();}在以可 如例 JdbcTemplateDemo 及面介 的中 案 專 IUserDAO UserDAO個一加增上別類 insertUsers() : 容 內 的 下 以 是 像 ,作 實 與 義 定 的 法 方...public int[] insertUsers(final List users) { String sql = "INSERT INTO user (name,age) VALUES(?,?)"; BatchPreparedStatementSetter setter = new BatchPreparedStatementSetter() { public void setValues( PreparedStatement ps, int i) throws SQLException { User user = (User) users.get(i); ps.setString(1, user.getName()); ps.setInt(2, user.getAge().intValue()); } public int getBatchSize() { return users.size(); } }; return jdbcTemplate.batchUpdate(sql, setter);}... 果如 JDBC 果如 , 能 功 的 它 用 使 接直則 , 話 的 理 處 次 批 援 支 式 程 動 驅則,援支不 Spring 。 理 處 次 批 擬 模以新 更 理 處 個 一 個 一 動 自 會 2
  26. 26. Spring 2.0 良信林(冊手術技 – http://openhome.cc )5.2.3 JdbcTemplate 查詢用使 JdbcTemplate 用使以可,時詢查行進 queryForXXX() ,法方等用使如例 queryForInt() :數筆料資的中格表 回傳法方 userjdbcTemplate.queryForInt("SELECT COUNT(*) FROM user"); 用使以可也 queryForObject() 回傳 如 例 , 件 物 果 結 的 後 詢 查 個 一 回 傳:件物 個一 StringString name = (String) jdbcTemplate.queryForObject( "SELECT name FROM USER WHERE id = ?", new Object[] {id}, java.lang.String.class);使以可則,料資筆多回傳果如,料資筆一單是都的回傳子例個兩面上 :如例,法方 queryForList() 用List rows = jdbcTemplate.queryForList( "SELECT * FROM user WHERE id=" + id.intValue());的中果結詢查表代件物 個每,件物 是的括包中 的回傳 List Map Map位欄用使要,值的中位欄得取要,容內位欄個多括包料資筆每,料資筆一 " :如例, ) (鍵 為作稱名 K ey "...Iterator it = rows.iterator();while(it.hasNext()) { Map userMap = (Map) it.next(); System.out.println(userMap.get("id")); System.out.println(userMap.get("name")); System.out.println(userMap.get("age")); ...}...26
  27. 27. Chapter 5 JDBC 援支易交、 作實以可您 org.springframework.jdbc.core.RowCallbackHandler 介下一改修如例,回傳再理處些一作先後之料資到詢查在,面 5.2.1 的 在,下如法方 的JdbcTemplateDemo中案專 UserDAO find() RowCallback- (Handler 的單簡作實中法方 的 processRow() ORM O bject-RelationalMapping :作動)...public User find(Integer id) { final User user = new User(); jdbcTemplate.query( "SELECT * FROM user WHERE id = ?", new Object[] {id}, new RowCallbackHandler() { public void processRow(ResultSet rs) throws SQLException { user.setId(new Integer(rs.getInt("id"))); user.setName(rs.getString("name")); user.setAge(new Integer(rs.getInt("age"))); } }); return user;}... 作實先以可則,件物的果結詢查多很回取要次一果如 org.springframe- :如例,面介work.jdbc.core.RowMapperpackage onlyfun.caterpillar;import java.sql.ResultSet;import java.sql.SQLException;import org.springframework.jdbc.core.RowMapper;public class UserRowMapper implements RowMapper { public Object mapRow(ResultSet rs, 27
  28. 28. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) int rowNum) throws SQLException { User user = new User(); user.setId(new Integer(rs.getInt("id"))); user.setName(rs.getString("name")); user.setAge(new Integer(rs.getInt("age"))); return user; }} 在 Spring 2.0 ,中 詢查,除移被經已別類作實其與面介 R esultReader受接接直在現法方 RowMapper :時法方 用使如例,例實 queryForObject()... public User find(Integer id) { User user = (User) jdbcTemplate.queryForObject( "select * from user where id=?", new Object[] {id}, new UserRowMapper()); return user; }... 用使已果結的回傳 UserRowMapper 為裝封之將,義定的 User 。件 物:範示個一的時法方 用使是下以 query()List users = jdbcTemplate.query("select * from user", new UserRowMapper());for(int i = 0; i < users.size(); i++) { User user = (User) users.get(i); System.out.println("tId:t" + user.getId()); System.out.println("tName:t" + user.getName()); System.out.println("tAge:n" + user.getAge());}28
  29. 29. Chapter 5 JDBC 援支易交、 為 裝封 已 並,果 結 的 來出詢 查 中 庫 料 資 從 了 括 包,中 件 物 的 回 傳 ListUser 。例實的別類5.2.4 JdbcTemplate 的 Lob 支援 ( 與 J DBC) ( 用使以可中 在 C lob C haracter large object B lob B inary large透以可中object 。存儲行進案檔位進二與案檔字文對針別分以,) S pring如 例(庫 料 資 定 特 理 處 免 避 以 , JdbcTemplate 與 CLOB 理處來 BLOB 過資 的 您 設 假 , 說 來 子 例 個 舉 。 題 問 異 差 、 的)Oracle 9i Clob B lob MySQL :下如格表庫料CREATE TABLE test ( id INT AUTO_INCREMENT PRIMARY, txt TEXT, image BLOB);料資至存儲之將想並,案檔位進二與案檔字文個一進讀別分在現設假 :如例, 用使以可則,中庫 JdbcTemplatefinal File binaryFile = new File("wish.jpg");final File txtFile = new File("test.txt");final InputStream is = new FileInputStream(binaryFile);final Reader reader = new FileReader(txtFile);JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);final LobHandler lobHandler = new DefaultLobHandler();jdbcTemplate.execute("INSERT INTO test (txt, image) VALUES(?, ?)", new AbstractLobCreatingPreparedStatementCallback(lobHandler) { protected void setValues(PreparedStatement pstmt, LobCreator lobCreator) throws SQLException,DataAccessException { lobCreator.setClobAsCharacterStream( pstmt, 1, reader, (int) txtFile.length()); 2
  30. 30. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) lobCreator.setBlobAsBinaryStream( pstmt, 2, is, (int) binaryFile.length()); } });reader.close();is.close();,時件物 立建在 AbstractLobCreatingPreparedStatementCallback 或 ( 於對,例實 LobHandler 個一遞傳要 MySQL M S SQL Server Oracle 的定特10g 於對,可即 用使邊這,) DefaultLobHandler Oracle 9i LOB用使,中作實法方 在。 OracleLobHandler用使以可,理處 setValues()與一第示表 、 引索,流串源來的 與 定設別分來LogCreator Blob Clob 1 2 。度 長 取 讀 定 指 並 , 置 位 的 元 字 位 佔 個 二 第 ?的下以用使以可,案檔為存另並,來出取讀料資將中庫料資從要果如 :式程final Writer writer = new FileWriter("test_bak.txt");final OutputStream os = new FileOutputStream(new File(wish_bak.jpg"));jdbcTemplate.query("SELECT txt,image FROM test WHERE id = ?", new Object[] {new Integer(1)}, new AbstractLobStreamingResultSetExtractor() { protected void streamData(ResultSet rs) throws SQLException, IOException, DataAccessException { FileCopyUtils.copy( lobHandler.getClobAsCharacterStream(rs, 1), writer); FileCopyUtils.copy( lobHandler.getBlobAsBinaryStream(rs, 2), os); } });writer.close();os.close(); 用使邊這在 FileCopyUtils 的 copy() 將,法方 LogHandler 流串的得取出輸案檔給接轉接直 FileWriter 、 F ileOutputStream 。件物3
  31. 31. 31 sf.run(); sf.compile(); dataSource, "SELECT COUNT(*) from user"); SqlFunction sf = new SqlFunction( : 子 例 個 一是面 下 , 數 筆 料 資 的 到詢查 示 表 數 整 個 一 傳 回 後然, COUNT() 行執以可如例, SQL Function 行執來用 SqlFunction 。例 實的 別類些這用使複重下境環的緒行執多在以可以所,) (全安緒行 T hread-safe 執為計設被們它,別類等 org.springframework.jdbc.object.MappingSqlQuery 、 org.springframework.jdbc.object.SqlUpdate 類 子其用使 以可您,作操 等序 程存 預、新更、詢 查的 ) R elational Database Management System ( RDBMS 表代,類象抽個是 org.springframework.jdbc.object.RdbmsOperation 。作操關相庫料 資行進來法方的它行執,例實個這用利複重以可就後之,譯編並別類的應 對相化例實接直或承繼先事要只,式程的面方作操庫料資計設來式方的向 導件物更以您讓,件套 org.springframework.jdbc.object 供提 Spring 。 式方作操的向 導件 物近接更 作操庫料資, 看來點觀 的們他從,節 細的 到 觸接須無就 們他 SQL ,用使員人發開給件物用重可的成完計設些這將,時計設庫料資行進在後之 立建, 件物作操的用 重可立建步一進以 可您, 中 在 , 些某 用重 Spring SQL SQL 是或,法語 到觸接用不員人發開式程些一讓想果如,法語 用使何 SQL 如悉熟須仍法方 個各的 JdbcTemplate 而然,術 技庫料資 的層底觸接用 不您 讓,節細 的理 處 JDBC 了裝 封它,看來法 方個各 的 上 就 JdbcTemplate 5.2.5 以物件方式進行操作 援支易交、 Chapter 5 JDBC
  32. 32. Spring 2.0 良信林(冊手術技 – http://openhome.cc )數參關相及以 、 RdbmsOperation 好定設在別類子的 DataSource S QL在 ,例實 個 這 用 使 複 重 以 可 就 後 之 , 譯 編 行 進 compile() 行執 先 須 必 , 後 中 改修如例, 裝封來 SqlFunction SQL 承繼以可時計設 5.2.1 JdbcTemplate-Demo :示 所 下 如 別 類 個 一 增 新 , 容 內 的 案 專 RdbmsDemo UserFunction.java package onlyfun.caterpillar; import javax.sql.DataSource; import org.springframework.jdbc.object.SqlFunction; public class UserFunction extends SqlFunction { public UserFunction(DataSource dataSource) { super(dataSource, "SELECT COUNT(*) from user"); compile(); } }參關相定設以可也您,作操新更的 個一示表來用別類 SqlUpdate SQL : 如 例 , 裝 封 的 行 進 來 它承繼 以 可 也 時 計 設 , 數 SQL RdbmsDemo UserUpdate.java package onlyfun.caterpillar; import java.sql.Types; import javax.sql.DataSource; import org.springframework.jdbc.object.SqlUpdate; public class UserUpdate extends SqlUpdate { public UserUpdate(DataSource dataSource) { super(dataSource, "INSERT INTO user (name,age) VALUES(?,?)"); int[] types = {Types.VARCHAR, Types.INTEGER};32
  33. 33. Chapter 5 JDBC 援支易交、 setTypes(types); compile(); }},型 類 據 數 的 入 插 要 所 元 字 位 佔 中 定 設 來 用 法 方 setTypes() SQL "?"每 ,詢查 行 進 來 數 引 為 作 列陣件 物 定 指 僅 以 可 , 時 法 方 update() 行執後之 : 用 使 麼 這 以 可 如 例 , 元 字 位 佔 代取 際 實 將 值 列 陣 個 一 "?"... SqlUpdate userUpdate = new UserUpdate(dataSource); ... userUpdate.update( new Object[] {user.getName(), user.getAge()});,別類個這用使接直少很常通但,作操詢查 個一示表別類 SqlQuery SQL以可,例實的別類 為裝封如例,理處些一作會,後之料資到詢查為因 User來 別類子的它用使 org.springframework.jdbc.object.MappingSqlMapping :如 例 , 作 動 個 這 行 進 RdbmsDemo UserQuery.javapackage onlyfun.caterpillar;import java.sql.ResultSet;import java.sql.SQLException;import javax.sql.DataSource;import org.springframework.jdbc.object.MappingSqlQuery;public class UserQuery extends MappingSqlQuery { public UserQuery(DataSource dataSource) { super(dataSource, "SELECT * FROM user"); compile(); } protected Object mapRow(ResultSet rs, 33
  34. 34. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) int rowNum) throws SQLException { User user = new User(); user.setId(new Integer(rs.getInt("id"))); user.setName(rs.getString("name")); user.setAge(new Integer(rs.getInt("age"))); return user; } } : 它 用 使 麼 這 以 可,後 之 別 類 個 這 好 計 設...SqlQuery userQuery = new UserQuery(dataSource);...List users = userQuery.execute();的回傳上際實,後法方 execute() 完行執 List 有會中 User ,例實的別類 。 料 資 筆 一 每的後 詢 查 了 裝 封 並 中 當下 一 寫 改 再 以 可,作 實 個 幾 的 上 以 合 配 IUserDAO 與面介 UserDAO :如例,作實 RdbmsDemo IUserDAO.java package onlyfun.caterpillar; import java.util.List; public interface IUserDAO { public void insert(User user); public List allUser(); public int count(); }34
  35. 35. Chapter 5 JDBC 援支易交、程的面方取存庫料資責負員人發開的他其有,員人發開式程是您設假您 則,別 類 與 、 的 上 以 了 供 提 並,式 UserFunction U serUpdate UserQuery 、 用重以可,寫撰何如是 的際實心關用不就 SQL UserFunction U serUpdate :別類 UserQuery 的您計設來別類 與 UserDAO RdbmsDemo UserDAO.javapackage onlyfun.caterpillar;import java.util.List;import javax.sql.DataSource;import org.springframework.jdbc.object.SqlFunction;import org.springframework.jdbc.object.SqlQuery;import org.springframework.jdbc.object.SqlUpdate;public class UserDAO implements IUserDAO { private SqlUpdate userUpdate; private SqlQuery userQuery; private SqlFunction userFunction; public void setDataSource(DataSource dataSource) { userUpdate = new UserUpdate(dataSource); userQuery = new UserQuery(dataSource); userFunction = new UserFunction(dataSource); } public void insert(User user) { userUpdate.update( new Object[] {user.getName(), user.getAge()}); } public List allUser() { return userQuery.execute(); } public int count() { return userFunction.run(); }} 3
  36. 36. Spring 2.0 良信林(冊手術技 – http://openhome.cc )物是 全 完 , 看 來 度 角 的 寫 撰 式 程 SQL 從,後之用重裝封 將 UserDAO作運看看來式程的單簡個寫以可,改修的式程合配,行進來式方的作操件 :常正否是 RdbmsDemo SpringDAODemo.java package onlyfun.caterpillar; import org.springframework.context.ApplicationContext; import org.springframework.context. support.ClassPathXmlApplicationContext; import java.util.List; public class SpringDAODemo { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( "beans-config.xml"); User user = new User(); user.setName("just933"); user.setAge(new Integer(26)); IUserDAO userDAO = (IUserDAO) context.getBean("userDAO"); userDAO.insert(user); System.out.println(" 數筆 : " + userDAO.count()); List list = userDAO.allUser(); for(int i = 0; i < list.size(); i++) { User next = (User) list.get(i); System.out.println("ntId:t" + next.getId()); System.out.println("tName:t" + next.getName()); System.out.println("tAge:t" + next.getAge()); } } }36
  37. 37. Chapter 5 JDBC 援支易交、 、 UserDAO 、 的中 UserUpdate 麼什為 U serQuery U serFunction 觀 個 一 有 還,外 之 作 實 例 範 化 簡 了 除 ? 呢 入 注 賴 依 用 使 不 等 IoC 依 個 來 要 都 一 十 二 七 三 管 不 件 物 個 每 ! 而 了 為 要 不:念 IoC IoC 的 長 冗 堆 大 一 有 會 將,上 件 物 的 賴 依 入 注 被,話 的 入 注 賴 Setter ,時賴依的同相入注要需件物的上以個兩有,是的議建。法方 。入注賴依行進來器容 Spring IoC 用使慮考才5.2.6 DataFieldMaxValueIncrementer與是好最置設的鍵主,鍵主定設要需會您,時中庫料資至料資入插在 用使以可您,中 在,關無值鍵務商 Spring org.springframework.jdbc.,值鍵主生產您為來support.incrementer.DataFieldMaxValueIncrementer如例,例實的庫料資同不對針多許有DataFieldMaxValueIncrementer 、 、DB2SequenceMaxValueIncrementer H sqlMaxValueIncrementer M ySQL- 、MaxValueIncrementer 、 OracleSequenceMaxValueIncrementer Postgre-、 的它作操以可您,SQLSequenceMaxValueIncrementer nextIntValue() 。值鍵主個一下生產來nextLongValue() 或 nextStringValue()5.2.7 Spring 2.0 的 NamedParameterJdbcTemplate您讓,別類 Spring 2.0 了增新中 在 NamedParameterJdbcTemplate名命的際實用使是而, 元字位佔用使必不,時述陳 的 JDBC SQL 寫撰在 ?您本原 如 例 , 份 部 料 資 的 動 變 會 中 留 保 來 ) N amed parameter SQL (數參 :詢 查 個 一 寫 撰 麼 這 是String sql = "SELECT * FROM user WHERE id=?";List rows = jdbcTemplate.queryForList(sql, new Object[] {id.intValue()}); 37
  38. 38. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) 用使以可在現 NamedParameterJdbcTemplate :式方的下以為寫改String sql = "SELECT * FROM user WHERE id=:userId";SqlParameterSource namedParameters = new MapSqlParameterSource("userId", id);NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);List rows = jdbcTemplate.queryForList(sql, namedParameters);用使是邊這在,式方定指的值際實 ":userId" 數參名命到意注以可也您。值際實與數參名命定指接直時構建在,SqlParameterSource Map : 如 例,值 際 實 的 數 參 名 命 個 多 定 指 來 件 物 用 使String sql = "INSERT INTO user (name,age) VALUES(:userName, :userAge)";Map namedParameters = new HashMap();namedParameters.put("userName", name);namedParameters.put("userAge", age);NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);jdbcTemplate.update(sql, namedParameters);個一據根以可也您 POJO ( P lain Old Java Object 名命為作值的件物):如 例 , 據 依 的 值 數 參String sql = "INSERT INTO user (name,age) VALUES(:name, :age)";SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(user);NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);jdbcTemplate.update(sql, namedParameters); 中其 " user" 是件物的考參所 JdbcTemplateDemo 。例實 的中案專 User將體具下以 的案專 JdbcTemplateDemo UserDAO 用使為寫改,別類NameParameterJdbcTemplate :式方的38
  39. 39. Chapter 5 JDBC 援支易交、 NamedParameterDemo UserDAO.javapackage onlyfun.caterpillar;import java.util.Iterator;import java.util.List;import java.util.Map;import javax.sql.DataSource;import org.springframework.jdbc.core.namedparam .BeanPropertySqlParameterSource;import org.springframework.jdbc.core.namedparam .MapSqlParameterSource;import org.springframework.jdbc.core.namedparam .NamedParameterJdbcTemplate;import org.springframework.jdbc.core.namedparam.SqlParameterSource;public class UserDAO implements IUserDAO { private NamedParameterJdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { jdbcTemplate = new NamedParameterJdbcTemplate(dataSource); } public void insert(User user) { String sql = "INSERT INTO user (name,age) VALUES(:name, :age)"; SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(user); jdbcTemplate.update(sql, namedParameters); } public User find(Integer id) { String sql = "SELECT * FROM user WHERE id=:userId"; SqlParameterSource namedParameters = new MapSqlParameterSource("userId", id); List rows = jdbcTemplate.queryForList(sql, namedParameters); Iterator it = rows.iterator(); if(it.hasNext()) { Map userMap = (Map) it.next(); Integer i = new Integer(userMap.get("id").toString()); 3
  40. 40. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) String name = userMap.get("name").toString(); Integer age = new Integer(userMap.get("age").toString()); User user = new User(); user.setId(i); user.setName(name); user.setAge(age); return user; } return null; } }5.2.8 Spring 2.0 的 SimpleJdbcTemplate中 用利以可則,本版的上以 是 的用使您果如 JDK 5.0 Spring 2.0這是能可您來原如例,能功) (型泛的供提所SimpleJdbcTemplate G eneric :料資詢查麼public User find(Integer id) { String sql = "SELECT * FROM user WHERE id=?"; RowMapper mapper = new RowMapper() { public Object mapRow(ResultSet rs, int rowNum) throws SQLException { User user = new User(); user.setId(new Integer(rs.getInt("id"))); user.setName(rs.getString("name")); user.setAge(new Integer(rs.getInt("age"))); return user; } }; JdbcTemplate simpleJdbcTemplate = new JdbcTemplate(this.getDataSource());4
  41. 41. Chapter 5 JDBC 援支易交、 return (User) jdbcTemplate.queryForObject(sql, mapper, id);} 用改若 SimpleJdbcTemplate :寫撰下如以可則,public User find(Integer id) { String sql = "SELECT * FROM user WHERE id=?"; ParameterizedRowMapper<User> mapper = new ParameterizedRowMapper<User>() { public User mapRow(ResultSet rs, int rowNum) throws SQLException { User user = new User(); user.setId(new Integer(rs.getInt("id"))); user.setName(rs.getString("name")); user.setAge(new Integer(rs.getInt("age"))); return user; } }; SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(this.getDataSource()); return simpleJdbcTemplate.queryForObject(sql, mapper, id);}在接直以可,能功的型泛到用使中當,到意注以可 mapRow()之法方 的 User 而,例實 回傳後 SimpleJdbcTemplate queryForObject() 以可也法方 將下以。例實 的果結詢查回傳接直 User JdbcTemplateDemo 的案專 :式方的UserDAO 用使為寫改 SimpleJdbcTemplate SimpleJdbcTemplateDemo UserDAO.javapackage onlyfun.caterpillar;import java.sql.ResultSet;import java.sql.SQLException;import javax.sql.DataSource;import org.springframework.jdbc.core.simple.ParameterizedRowMapper;import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; 41
  42. 42. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) public class UserDAO implements IUserDAO { private SimpleJdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { jdbcTemplate = new SimpleJdbcTemplate(dataSource); } public void insert(User user) { String sql = "INSERT INTO user (name,age) VALUES(?, ?)"; String name = user.getName(); Integer age = user.getAge(); jdbcTemplate.update(sql, new Object[] {name, age}); } public User find(Integer id) { String sql = "SELECT * FROM user WHERE id=?"; ParameterizedRowMapper<User> mapper = new ParameterizedRowMapper<User>() { public User mapRow(ResultSet rs, int rowNum) throws SQLException { User user = new User(); user.setId(new Integer(rs.getInt("id"))); user.setName(rs.getString("name")); user.setAge(new Integer(rs.getInt("age"))); return user; } }; return jdbcTemplate.queryForObject(sql, mapper, id); } }42
  43. 43. 43 :如例 ,行執的有所消撤來 rollback() 行執 則 , 誤 錯 生 發間中 果 如 , 更 變 出 送 來 commit()的 Connection 行執行自,後句語 的串連一達下在,數引 SQL false 它 定 給,法 方 setAutoCommit() 的 Connection 作 操 以 可,中 在,現 JDBC 實性 子 原 的 易 交 看 看 來先首 。 理 管 易 交 用 使 何 如 紹介將邊這在JDBC 。 的 來下錄 記 被 是 須 必 易 交 筆 這,後之易交筆一某在,) D urable (的續持可是須必還易交。在存的此彼 到識意需不上本基易交個兩,作動的款提與款存行進時同易交筆兩有能可 A 中戶帳 在如例,) I solated ( 的 離 隔 是 須 必 間 之此 彼 易 交 個 每 。 額 金 的 A B 款 存 戶 帳 於 大 能 不 額 金 的 款 取 戶 帳 ,額 金 帳 轉的 戶 帳個 兩 ,中 子 例 的 戶帳行銀在如例,) C onsistent (性致一的源資與參所持保須必還易交 。 敗 失 帳 轉 次 此 則,敗 失 作 動 個 一 有 果 如 ,功成須必作動個兩,額金的帳轉上加戶帳的行銀 在、款扣戶帳的行銀 B A B 從為作動的作要,行銀 至帳轉行銀 從戶客個一,子例的單簡個舉 A SQL 。消撤令指 的過行執有所前先則, 誤錯有 行一中其如例(因原個 ) SQL SQL 某為因 若 , 功 成 行 執 部 全 須 必 令 指 組 一 這 , 令 指 組 一 是 就 , 說 SQL 來 例 實 的 取 存 庫 料 資 以 , 元 單 作 工 的 作 操) A tomic (子 原 組 一 是 易 交 5.3.1 Spring 對交易的支援 。理管易交的 Spring 紹介,例為易交 JDBC 以 節這, 型 模 程 編 的 致 一 了供提 作 實 易 交 的 同 不 為 ,) D eclarative transaction management (理管易交的式告宣與) ment P rogrammatic transaction manage- (理 管易 交 的式 程編供提 Spring 5.3 JDBC 交易管理 援支易交、 Chapter 5 JDBC
  44. 44. Spring 2.0 良信林(冊手術技 – http://openhome.cc )try { ..... connection.setAutoCommit(false); ..... // 串連一 SQL 作操 connection.commit();} catch(SQLException) { // 更變有所消撤,誤錯生發 connection.rollback();} 在 Spring 對中 JDBC ,裝封以加理管易交的 S pring 其象抽的理管易交 於在 鍵關 org.springframework.transaction.PlatformTransactionManager:現實的面介...public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException;}如例,別類現實易交的體具多許有面介 PlatformTransactionManager 、 、DataSourceTransactionManager H ibernateTransactionManager J doTrans- 於賴依由藉,等actionManager J taTransactionManager 、 PlatformTran-發 開讓 以 可 上 理 管 易 交 在sactionManager ,現實術技的種各及面介 S pring 。 術 技 理 管 易 交 的 同不是 的 用 使 所 使 即 , 型模程 編 的 致 一 用 使 員 人是都 常 通 敗 失 的 易 交 。 TransactionException 是 Unchecked Exception例 捉捕要 否 是 擇 選 行 自 您 讓而, 理 處 要 定 一 您 迫 強 不 S pring ,誤錯的命致 。外44
  45. 45. 4 。務服理管易交去移可即,定設下一改修上案檔定設在要只,候時的理管易交要需不在,中之理管易交入納被正它道知不並,看來 API度 角 的 件 物 從,中 之 式 程 入 介 用 不 以 可 關 相 的 理 管 易 交 是處好 Spring,理 管 易 交 的 式 告 宣 用 採,制 控 的 度 粒 細 要 需 不 並 易 交,下 況 情 的 數 多 而 然 理管易交的式告宣 。制控易交的度粒細現實以可,等束結時何易交、機時的作操消撤、始開時何易交現實行自您讓是就也,界邊的易交制控的楚清以可理管易交的式程編 理管易交的式程編 :) D eclarative transaction management (理 管 易 交 的 式 告 宣 與) P rogrammatic transaction management (理管易交的式程編供提 Spring } boolean isRollbackOnly(); void setRollbackOnly(); boolean isNewTransaction(); public interface TransactionStatus { ... :態狀 的易交查調或行執的易交制控它由藉以可您,易交的在存經已或起發易交 的新個一著表代 T ransactionStatus ,等) (讀唯、) ( R ead-only T imeout 時超、) P ropagation behavior (為行播傳、) (度程離隔的 I solation level 易交了義定例實的面介 ,件物T ransactionDefinition 個 TransactionStatus 一傳回來件物 TransactionDefinition 個一據根法方 getTransaction() 援支易交、 Chapter 5 JDBC
  46. 46. Spring 2.0 良信林(冊手術技 – http://openhome.cc )5.3.2 JDBC 編程交易管理 用使接直是一,理管易交的式程編現實式方種兩供提 Spring Platform- 用使是二,現實TransactionManager org.springframework.transaction. 。support.TransactionTemplate實的它用使邊這在, 用使何如看看來先 PlatformTransactionManager中 的前之下一寫改以可, 別類現 DataSourceTransactionManager 5.2.1類 下一改修,能功理管易交有具它讓,案專JdbcTemplateDemo UserDAO insert() :範示作來法方 的別 ProgrammaticTransactionDemo UserDAO.java package onlyfun.caterpillar; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.sql.DataSource; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc. datasource.DataSourceTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction. support.DefaultTransactionDefinition; public class UserDAO implements IUserDAO { private DataSourceTransactionManager transactionManager; private DefaultTransactionDefinition def; private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); transactionManager = new DataSourceTransactionManager(dataSource); // 義定的易交立建46
  47. 47. Chapter 5 JDBC 援支易交、 def = new DefaultTransactionDefinition(); def.setPropagationBehavior( TransactionDefinition.PROPAGATION_REQUIRED);}public void insert(User user) { String name = user.getName(); int age = user.getAge().intValue(); TransactionStatus status = transactionManager.getTransaction(def); try { jdbcTemplate.update("INSERT INTO user (name,age) " + "VALUES(" + name + "," + age + ")"); //的面下 SQL 易交試測以用,誤錯有 jdbcTemplate.update("INSER INTO user (name,age) " + "VALUES(" + name + "," + age + ")"); } catch(DataAccessException e) { transactionManager.rollback(status); throw e; } transactionManager.commit(status);}public User find(Integer id) { List rows = jdbcTemplate.queryForList( "SELECT * FROM user WHERE id=" + id.intValue()); Iterator it = rows.iterator(); if(it.hasNext()) { Map userMap = (Map) it.next(); Integer i = new Integer( userMap.get("id").toString()); String name = userMap.get("name").toString(); Integer age = new Integer( userMap.get("age").toString()); User user = new User(); user.setId(i); user.setName(name); 47
  48. 48. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) user.setAge(age); return user; } return null; } }易交行進來 insert() 了用使中法方 在 DataSourceTransactionManager 在, 的易交行進會中塊區 則,外例了生發果如,理管 catch Rollback insert()實 此 因 ,) 個 一 了 寫 少 法 方 意 注 ( 的誤 錯 入 寫 意 故 中 法 方 SQL INSERT T 。 中 庫 料 資 至存儲 被 會 不 並 料 資 上 際 格 表 的 易 交 援 支 立 建 須 必,理 處 易 交 行 進 庫 料 資 MySQL 用使要 如 的格 表立建來用邊這,型類格表的 InnoDB 如例,型類 SQL :示所下 CREATE TABLE user ( id INT(11) NOT NULL auto_increment PRIMARY KEY, name VARCHAR(100) NOT NULL default , age INT ) TYPE = InnoDB; 用 使 是 法 方 的 理 管易交 式 程 編 現 實 個 一 另 TransactionTemplate 它,:示所下如,例實 TransactionManager 個一要需...TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);...transactionTemplate.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { return jdbcTemplate.update("INSERT INTO user (name,age) " + "VALUES(" + name + "," + age + ")");48
  49. 49. Chapter 5 JDBC 援支易交、 }});行 進會則 , 外 例 了 生 發 果 如 Rollback 傳回 有 沒 果 如 , 易 交 交 提 則 否 , 用使以可也則,值 TransactionCallbackWithoutResult :...transactionTemplate.execute( new TransactionCallbackWithoutResult() { public void doInTransactionWithoutResult( TransactionStatus status) { . ... } });5.3.3 JDBC 宣告交易管理易交告宣用使。成完來架框 的它於賴依理管易交的式告宣 Spring AOP不件物 ,說來體具,件組的發開所您入侵不理管易交,是處好的理管 D AO系於屬是理管易交為因,此如當應也上實事,中之理管易交在正到識意會的略策理管易交變改要想果如,份部一的輯邏務商是不而,務服的面層統 。 可 即 態 組 新 重 中檔義 定 在 要 需 只 也 , 話在,下一改修案專 中 將以可,說來子例個舉 5.2.1 JdbcTemplateDemo簡 個一, 務 服 的 理 管 易 交 入加它 為 以 可 , 下 況 情 的 別 類 UserDAO 改修不對 理 管 易 交 的 入 介 要 定 指, TransactionProxyFactoryBean 用使是法方的單 : 示所下 如 , 改 修 案 檔 義 定在要 需 這 , 法 方 其 及 象 DeclarativeTransactionDemo beans-config.xml<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans 4
  50. 50. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="dataSource" class="org.springframework.jdbc. → datasource.DriverManagerDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/demo"/> <property name="username" value="caterpillar"/> <property name="password" value="123456"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc. → datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="userDAO" class="onlyfun.caterpillar.UserDAO"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="userDAOProxy" class="org.springframework.transaction. → interceptor.TransactionProxyFactoryBean"> <property name="proxyInterfaces"> <list> <value>onlyfun.caterpillar.IUserDAO</value> </list> </property> <property name="target" ref="userDAO"/> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> </props> </property> </bean>
  51. 51. Chapter 5 JDBC 援支易交、</beans> TransactionProxyFactoryBean 個一要需 TransactionManager 這於由, , JDBC 用使以所, 用使邊 DataSourceTransactionManager T ransaction-易交,象對的理代要定指性屬ProxyFactoryBean ,件物理代個是 " target"屬 用使 是 邊 這 , 後 前 法 方的定 指 入 介 動 自 會 理 管 "transactionAttributes"您 ,理管 易 交 入 納 要 都 的 頭 開 稱 名 法 方 定 指 示 表 " insert*" insert ,定指性操的前先有所則,誤錯生發中程過行執法方在果如,名全法方定指以可也 。 交 提常正 則 否 , 回 撤 動 自 作目在示表, "insert*" 了定指上法方等 "PROPAGATION_REQUIRED"義意數常的關相,的新個一立建就在存不易交果如,作操行執中易交的前個多上加以可您。到找中面介 API 中件文 在以可都 TransactionDefinition個某定指是者或,讀唯上加以可如例,隔區 號逗用使間中,義定易交 "," :作 操 回 撤 時 生 發 外 例PROPAGATION_REQUIRED,readOnly,-MyCheckedException操消撤時外例定指生發示表,時 上加面前 MyCheckedException "-" 。 交提即 立 時 外 例 生 發 示 表 , 上 加 面 前 果 如 , 作 "+" 得取是的做要以所,了理代 " userDAO" 被 " userDAOProxy"於由 " user-DAOProxy" :如例, " userDAO" 是不而, DeclarativeTransactionDemo SpringDAODemo.javapackage onlyfun.caterpillar;import org.springframework.context.ApplicationContext;import org.springframework.context. support.ClassPathXmlApplicationContext;public class SpringDAODemo { 1
  52. 52. Spring 2.0 良信林(冊手術技 – http://openhome.cc ) public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( "beans-config.xml"); User user = new User(); user.setName("caterpillar"); user.setAge(new Integer(30)); IUserDAO userDAO = (IUserDAO) context.getBean("userDAOProxy"); userDAO.insert(user); user = userDAO.find(new Integer(1)); System.out.println("name: " + user.getName()); }}的同不定設以可也您 TransactionInterceptor ,節細理管的多更到得來 :如例<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="dataSource" class="org.springframework.jdbc. → datasource.DriverManagerDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/demo"/> <property name="username" value="caterpillar"/> <property name="password" value="123456"/>2
  53. 53. Chapter 5 JDBC 援支易交、 </bean> <bean id="transactionManager" class="org.springframework.jdbc. → datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="userDAO" class="onlyfun.caterpillar.UserDAO"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="transactionInterceptor" class="org.springframework.transaction. → interceptor.TransactionInterceptor"> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributeSource" value="onlyfun.caterpillar.UserDAO.insert*= → PROPAGATION_REQUIRED "/> </bean> <bean id="userDAOProxy" class="org.springframework.aop. → framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <list> <value>onlyfun.caterpillar.IUserDAO</value> </list> </property> <property name="target" ref="userDAO"/> <property name="interceptorNames"> <list> <value>transactionInterceptor</value> </list> </property> </bean></beans>在接直則,理管易交要需再不來後使即 Bean ,可 即 置 配 改 修 中 檔 義 定 。 作 動 等 譯 編 新重行 進 式 程 改 修 用 不 而 3

×