SQLMapAPI力求簡潔。它為程式員提供4種功能:配置一個SQLMap,執行SQLupdate操作,執行查詢語句以取得一個對象,以及執行查詢語句以取得一個對象的List。配置SQLMap一旦您創建了SQLMapXML定義文件和SQLMap配置文件,配置SQLMap就是一件極其簡單的事情。SQLMa...
SQL Map API 力求簡潔。它為程式員提供 4 種功能:配置一個 SQL Map,執行 SQL update操作,執行查詢語句以取得一個對象,以及執行查詢語句以取得一個對象的 List。
- 配置 SQL Map
一旦您創建了 SQL Map XML 定義文件和 SQL Map 配置文件,配置 SQL Map 就是一件 極其簡單的事情。SQL Map 使用 XmlSqlMapClientBuilder 來創建。這個類有一個靜態方法 叫 buildSqlMap。方法 buildSqlMap 簡單地用一個 Reader 對象為參數,讀入 sqlMap-config.xml 文件(不必是這個文件名)的內容。
1 String resource = “com/ibatis/example/sqlMap-config.xml”; 2 Reader reader = Resources.getResourceAsReader (resource); 3 SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMap(reader);
- 事務處理
預設情況下 ,調用 SqlMapClient 對象的任 意 executeXxxx() 方法將 預設地自 動 COMMIT/ROLLBACK。這意味著每次調用 executeXxxx()方法都是一個獨立的事務。這確實 很簡單,但對於需要在同一個事務中執行多個語句的情況(即只能同時成功或失敗),並不 適用。這正是事務處理要關心的事情。
如果您在使用 Global Transaction(在 SQL Map 配置文件中設置),您可以使用自動提交 並且可以得到在同一事務中執行的效果。但為了提高性能,最好是明確地劃分事務的範圍, 因為這樣做可以減少連接池的通訊流量和資料庫連接的初始化。
SqlMapClient 對象擁有讓您定義事務範圍的方法。使用下麵 SqlMapClient 類的方法,可 以開始、提交和/或回退事務:
1 public void startTransaction () throws SQLException
public void commitTransaction () throws SQLException
public void endTransaction () throws SQLException開始一個事務,意味著您從連接池中得到一個連接,打開它並執行查詢和更新 SQL 操 作。使用事務處理的例子如下:
1 private Reader reader = new Resources.getResourceAsReader( "com/ibatis/example/sqlMapconfig.xml"); 2 private SqlMapClient sqlMap = XmlSqlMapBuilder.buildSqlMap(reader); 3 public updateItemDescription (String itemId, String newDescription) throws SQLException { 4 try { 5 sqlMap.startTransaction (); 6 Item item = (Item) sqlMap.queryForObject ("getItem", itemId); 7 item.setDescription (newDescription); sqlMap.update ("updateItem", item); sqlMap.commitTransaction (); 8 } finally { 9 10 sqlMap.endTransaction (); 11 12 } 13 14 }
註意!事務不能嵌套。在調用 commit()或 rollback()之前,從同 一線程多次調用.startTransaction,將引起拋出例外。換句話說,對於每個 SqlMap 實例,每個線程最多只能打開一個事務。
註意!SqlMapClient 事務處理使用 Java 的 ThreadLocal 保存事務對象。這意味著在處理 事務時,每個調用 startTransaction()的線程,將得到一個唯一的 Connection 對象。將一個 Connection 對象返回數據源(或關閉連接)唯一的方法是調用 commitTransaction()或 rollbackTransaction()方法。否則,會用光連接池中的連接並導致死鎖。
-
自動的事務處理
雖然極力推薦使用明確劃分的事務範圍,在簡單需求(通常使只讀)的情況下,可以使 用簡化的語法。如果您沒有使用 startTransaction(),commitTransation()和 rollbackTransaction()方法來明確地劃分事務範圍,事務將會自動執行。例如:
1 private Reader reader = new Resources.getResourceAsReader 2 3 ("com/ibatis/example/sqlMapconfig.xml"); 4 5 private SqlMapClient sqlMap = XmlSqlMapBuilder.buildSqlMap(reader); 6 7 public updateItemDescription (String itemId, String newDescription) throws SQLException { 8 9 try { 10 11 Item item = (Item) sqlMap.queryForObject ("getItem", itemId); 12 13 item.setDescription (“TX1”); 14 15 //No transaction demarcated, so transaction will be automatic (implied) 16 17 sqlMap.update ("updateItem", item); item.setDescription (newDescription); item.setDescription (“TX2”); 18 //No transaction demarcated, so transaction will be automatic (implied) 19 20 sqlMap.update("updateItem", item); 21 22 23 24 } catch (SQLException e) { 25 26 throw (SQLException) e.fillInStackTrace(); 27 28 } 29 30 }
註意!使用自動事務處理要非常小心。雖然看起來很有吸引力,但如果有多個數據更新操作要在同一事務中處理時,您會遇到麻煩。在上面的例子中,如果第二個“updateItem”操作失敗,第一個“updateItem”操作仍然會執行,description 會更新成“TX1”。
-
全局(分散式)事務
SQL Map 框架支持全局事務。全局事務也叫分散式事務,它可以允許您在同一事務中 更新多個資料庫(或其他符合 JTA 規範的資源),即同時成功或失敗。
* External/Programmatic Global 事務
您可以選擇外部管理或手工編程管理全局事務,或實現一個象 EJB 一樣的架構。使用 EJB,您可以通過使用 EJB 的描述文件定義事務範圍。要支 持外部管理或手工編程管理全局事務,必須在 SQL Map 配置文件中(參見前面章節的內容) 設定<transactionManager>的 type 屬性為 EXTERNAL。使用外部管理的全局事務,SQL Map 事務控制方法變得有的多餘,因為事務的開始、提交和回退都由外部的事務管理器來控制。 但是,使用 SqlMapClient 的 startTransaction(),commitTransaction()或 rollbackTransaction()來劃分事務範圍(相對於自動的事務處理),還是對提高性能有幫助。繼續使用這些方 法,可以保持編程規範的一致性。另一個好處是,在某些情況下,您可能需要改變關閉資源 的順序(不幸的是,不同的應用伺服器和事務管理器具有不同的規則)。除了這些考慮,要 使用全局事務,不需要改變您的 SQL Map 代碼。
* 受管理的(Managed)全局事務
SQL Map 框架也可以為您管理全局事務。要支持受管理的全局事務,必須在 SQL Map 配置文件中設定<transactionManager>的 type 屬性為 JTA,並設定“UserTransaction”屬性為 JNDI 的全名,以使 SqlMapClient 實例能找到 UserTransaction 對象。
使用全局事務編程,代碼沒有多大的不同,但有幾個小小的地方要註意。例如:
1 try { 2 3 orderSqlMap.startTransaction(); storeSqlMap.startTransaction(); orderSqlMap.insertOrder(…); orderSqlMap.updateQuantity(…); 4 5 storeSqlMap.commitTransaction(); 6 7 orderSqlMap.commitTransaction(); 8 9 } finally { 10 11 try { 12 13 storeSqlMap.endTransaction() 14 15 } finally { 16 17 orderSqlMap.endTransaction() 18 19 } 20 21 }
上面的例子中,假設我們通過兩個 SqlMapClient 來使用兩個不同的資料庫。第一個開始事務的 SqlMapClient(orderSqlMap)同時也開始了一個全局事務。在這之後,所有其他的操作將被看作是這個全局事務的一部分,直到同一個 SqlMapClient(orderSqlMap)調用 commitTransaction()或 rollbackTransaction(),屆時全局事務被提交並完成其他所有的操 作。
警告!雖然這些看起來很簡單,但記住不要濫用全局(分散式)事務,這點很重要。這 樣做既有性能方面的考慮,同時也是因為全局事務會讓應用伺服器和資料庫驅動程式的設置 變得更複雜。雖然看起來簡單,您可能還是會遇到一些困難。
-
批處理
如果要執行很多非查詢(insert/update/delete)的語句,您可能喜歡將它們作為一個批處 理來執行,以減少網路通訊流量,並讓 JDBC Driver 進行優化(例如壓縮)。SQL Map API 使用批處理很簡單,可以使用兩個簡單的方法劃分批處理的邊界:
1 sqlMap.startBatch(); 2 //…execute statements in between 3 sqlMap.executeBatch();
當調用 endBatch()方法時,所有的批處理語句將通過 JDBC Driver 來執行。