1. 程式人生 > >iBATIS SQL Maps之配置SQL Map、事務處理和批處理。

iBATIS SQL Maps之配置SQL Map、事務處理和批處理。

配置SQL Map

一旦您建立了SQL Map XML定義檔案和SQL Map配置檔案,配置SQL Map就是一件極其簡單的事情。Sql Map使用XmlSqlMapClientBuilder來建立。這個類有一個靜態方法叫buildSqlMap。方法buildSqlMap簡單地用一個Reader物件為引數,讀入sqlMap-config.xml檔案(不必是這個檔名)的內容。

String resource = "com/ibatis/example/sqlMap-config.xml";

Reader reader = Resource.getResourceAsReader(resource);

SqlMapClientsqlMap = SqlMapClientBuilder.buildSqlMap(reader);

事務處理

預設情況下,呼叫SqlMapClient物件的任意executeXxxx()方法將預設地自動COMMIT/ROLLBACK。這意味著每次呼叫executeXxxx()方法都是一個獨立的事務。這確實很簡單,但對於需要在同一個事務中執行多個語句的情況(即只能同時成功或失敗),並不適用。這正是事務處理要關心的事情。

如果您在使用Global Transaction(在SQL Map配置檔案中設定),您可以使用自動提交併且可以得到在同一事務中執行的效果。但為了提高效能,最好是明確地劃分事務的範圍,因為這樣做可以減少連線池的通訊流量和資料庫連線的初始化。

SqlMapClient物件擁有讓您定義事務範圍的方法。使用下面SqlMapClient類的方法,可以開始、提交和/或回退事務:

public void startTransaction() throws SQLException;

public void commitTransaction() throws SQLException;

public void endTransaction() throws SQLException;

開始一個事務,意味著您從連線池中得到一個連線,開啟它並執行查詢和更新SQL操作。使用事務處理的例子如下:

private Reader reader = new Resources.getResourceAsReader("com/ibatis/example/sqlMap-config.xml");

private SqlMapClientsqlMap = XxmlSqlMapBuilder.buildSqlMap(reader);

public updateItemDescription(String itemId, String newDescription) throws SQLException {

try{

sqlMap.startTransaction();

Item item = (Item) sqlMap.queryForObject("getItem" , itemId);

item.setDescription(newDescription);

sqlMap.update("updateItem" , item);

sqlMap.commitTransaction();

} finally {

sqlMap.endTransaction();

}

}

注意!事務不能巢狀。在呼叫commit()或rollback()之前,從同一執行緒多次呼叫.startTransaction,將引起丟擲例外。換句話說,對於每個SqlMap例項,每個執行緒最多隻能開啟一個事務。

注意!SqlMapClient事務處理使用Java的ThreadLocal儲存事務物件。這意味著在處理事務時,每個呼叫startTransaction()的執行緒,將得到一個唯一的Connection物件。將一個Connection物件返回資料來源(或關閉連線)唯一的方法是呼叫commitTransaction()或rollbackTransaction()方法。否則,會用光連線池中的連線並導致死鎖。

自動的事務處理

雖然極力推薦使用明確劃分的事務範圍,在簡單需求(通常是隻讀)的情況下,可以使用簡化的語法。如果您沒有使用startTransaction(),commitTransaction()和rollbackTransaction()方法來明確地劃分事務範圍,事務將會自動執行。例如:

private Reader reader = new Resources.getResourceAsReader("com/ibatis/example/sqlMap-config.xml");

private SqlMapClientsqlMap = XxmlSqlMapBuilder.buildSqlMap(reader);

public updateItemDescription(String itemId, String newDescription) throws SQLException {

try{

Item item = (Item) sqlMap.queryForObject("getItem" , itemId);

item.setDescription("TX1");

// No transaction demarcated, so transaction will be automatic(implied)

sqlMap.update("updateItem" , item);

item.setDescription(newDescription);

item.setDescription("TX2");

// No transaction demarcated, so transaction will be automatic(implied)

sqlMap.update("updateItem" , item);

} catch(SQLException e){

throw (SQLException)e.filllnStackTrance();

}

}

注意!使用自動事務處理要非常小心。雖然看起來很有吸引力,但如果有多個數據更新操作要在同一事務中處理時,您會遇到麻煩。在上面的例子中,如果第二個“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物件。 使用全域性事務程式設計,程式碼沒有多大的不同,但有幾個小小的地方要注意。例如: try { orderSqlMap.startTransaction(); storeSqlMap.startTransaction(); orderSqlMap.insertOrder(...); orderSqlMap.updateQuantity(...); storeSqlMap.commitTransaction(); orderSqlMap.commitTransaction(); } finally { try { storeSqlMap.endTransaction(); } finally { orderSqlMap.endTransaction(); } } 上面的例子中,假設我們通過兩個SqlMapClient來使用兩個不同的資料庫。第一個開始事務的SqlMapClient(orderSqlMap)同時也開始了一個全域性事務。在這之後,所有其他的操作將被看做是這個全域性事務的一部分,直到同一個SqlMapClient(orderSqlMap)呼叫commitTransaction()或rollbackTransaction(),屆時全域性事務被提交併完成其他所有的操作。 警告!雖然這些看起來很簡單,但記住不要濫用全域性(分散式)事務,這點很重要。這樣做既有效能方面的考慮,同時也是因為全域性(分散式)事務,這點很重要。這樣做既有效能方面的考慮,同時也是因為全域性事務會讓應用伺服器和資料庫驅動程式的設定變得更復雜。雖然看起來簡單,您可能還是會遇到一些困難。記住,EJB擁有更多廠商和工具支援。對於需要分散式事務的應用,最好還是使用Session EJB。

批處理

如果要執行很多非查詢(insert/update/delete)的語句,您可能喜歡講他們作為一個批處理來執行,以減少網路通訊流量,並讓JDBC Driver進行優化(例如壓縮)。SQL Map API使用批處理很簡單,可以使用兩個簡單的方法劃分批處理的邊界: sqlMap.startBatch(); // ...execute statements in between sqlMap.executeBatch(); 當呼叫endBatch()方法時,所有的批處理語句將通過JDBC Driver來執行。