Successfully reported this slideshow.
Your SlideShare is downloading. ×

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

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
。援支些一的
上易交及以取存      JDBC 於        紹介來子例的際實些一以將,中節
                      Spring
章 個 這 在。能 功 的 務 服 關 相 等 易 交 得 獲 易 輕 並,式 方 用...
2
                                 }
                                     public void delete(User user);
                 ...
Chapter 5 JDBC      援支易交、

作 實 以 可 別 類 的取存 庫 料 資 行 進 上 際 實          IUserDAO   一義定如例,面介
             :別類
         UserDAO ...
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement
Advertisement

Check these out next

1 of 68 Ad
Advertisement

More Related Content

Slideshows for you (20)

Viewers also liked (18)

Advertisement

Similar to Spring 2.0 技術手冊第五章 - JDBC、交易支援 (20)

Advertisement

Recently uploaded (20)

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.core org.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.java package 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.java package 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 ); 據根著接,料資筆一入存中格表 的庫料資在先會果結行執的式程 user id 。字文的 示顯會果結後最,料資的入存所前先出詢查值 "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個這上換的單簡以可也, 的 DataSource 16
  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; } } ,動變用不都檔定設與式程的它其,了以可就 寫改要只 UserDAO Spring 由藉是要主,的示所稱名其如一 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.PreparedStatementSetter package 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- :面介 PreparedStatementSetter 24
  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() :數筆料資的中格表 回傳法方 user jdbcTemplate.queryForInt("SELECT COUNT(*) FROM user"); 用使以可也 queryForObject() 回傳 如 例 , 件 物 果 結 的 後 詢 查 個 一 回 傳 :件物 個一 String String 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-Relational Mapping :作動) ... 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.RowMapper package 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 援支易交、 為 裝封 已 並,果 結 的 來出詢 查 中 庫 料 資 從 了 括 包,中 件 物 的 回 傳 List User 。例實的別類 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 ); 料資至存儲之將想並,案檔位進二與案檔字文個一進讀別分在現設假 :如例, 用使以可則,中庫 JdbcTemplate final 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.java package 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.java package 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.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.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.java package 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.java package 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
  54. 54. 4 易交的存現 停暫就 話的有果 如,行進中 易交在 應不出指 PROPAGATION_NOT_SUPPORTED 外例 出丟就 話的有果 如,行進中 易交在 應不出指 PROPAGATION_NEVER 同則 PROPAGATION_REQUIRED , 話 的 是 不 果 如,行 進中易 交的狀 巢個一在 PROPAGATION_NESTED 外例出 丟 則否,行進中 易交 的存現 個一在 須必法方 PROPAGATION_MANDATORY 明說 為行播傳 明說為行播傳易交 5.1 表 :個幾出列下以,明說與數常的應對相到找上明 說件文 的 API TransactionDefinition 在 以 可 ,為 行 播 傳 個 幾 了 義 定 Spring 。行 進 中 易 交 在 要 否 是 法 方 者 或,停 暫 被 該 易 交 時 何 或,易 交 的 新 個 一 始 開 該時何知告它,) B oundaries (界邊之上法方於用應易交了義定為行播傳 ) P ropagation behavior (為行播傳 :數 參 個 幾 的 下 以 作 分 性 屬 易 交 中 Spring 在 ,略策 的 上 法 方 至 用 應 易 交述描於在就然自) T ransaction attribute (性屬易交的 ,界邊為 S pring 法方以是易交式告宣而因,理管易交的式告宣成完來 用使 AOP Spring 5.3.4 交易的屬性介紹 。 括包須必中定設 spring-aop.jar Classpath 的您得記請,時 式 程 的 上 以 行 執 以 所 ,成 達 來 Spring AOP 用利是理管易交告宣 ) – http://openhome.cc 良信林(冊手術技 Spring 2.0

×