ibatis 框架介紹及使用詳解

 

iBATIS 是什麼?

這一節將描述 iBATIS 中的單獨的 API,以及爲什麼您可能使用它們,並瞭解 iBATIS 優於其他數據庫映射框架的優點。

iBATIS 框架

簡言之,iBATIS 由兩個單獨的框架組成。可以將 Data Mapper 框架專門用於 OR 映射,OR 映射是 Java 域對象到數據庫中關係表的映射。DAO 框架爲應用程序提供了一個簡潔一致的訪問基礎數據的方法。

iBATIS Data Mapper 框架 (Data Mapper)

Data Mapper 是執行 SQL 並將結果映射回對象的框架,它使您不必手工執行此操作。

Data Mapper 框架不要求使用任何特殊版本的 Java 對象。您不必實現任何接口或生成任何代碼,不必爲其他一些基本對象創建子類或遵循任何奇怪的慣例,也不必學習特定於該框架的輔助查詢語言。

可以使用一個簡單並直接的 XML 格式來定義 iBATIS 將 Java 對象映射到數據庫的方式。可以直接用 SQL 定義所需的具體查詢,並有選擇地使用任何特定於正使用的數據庫引擎的專有 SQL。此功能允許您使用您想要的方式來映射對象和執行連接。

iBATIS Data Access Objects 框架(DAO 框架)

DAO 框架的主要目標是抽象化應用程序的數據訪問層和持久層的表示方式位置 ,使它們遠離應用程序的業務邏輯。DAO 框架允許在應用程序中定義負責數據中心操作的接口。

例如,如果應用程序使用直接的 Java Database Connectivity (JDBC) 來獲得持久性,則 DAO 框架的目標是抽象這些類和接口(比如 ConnectionPreparedStatementResultSet )的使用,使它們遠離應用程序,並下移到持久層中。

如果應用程序出於某種原因使用 HTTP GET 和 POST 來獲得和存儲數據,則 DAO 框架的用途變成抽象化類(比如 HttpUrlConnection )的使用,使它們遠離應用程序的業務層。然後應用程序可以使用 DAO 接口在數據上執行操作,這些接口的實現被抽象化,遠離業務邏輯。這些實現可以從數據庫、Web 服務或其他任何源中獲得數據。

DAO 框架不依賴於 Data Mapper 框架的使用。您可以選擇在一個項目中同時使用這兩個框架(成對使用它們相當不錯),或者也可以單獨使用每個框架。這一教程系列將展示單獨使用框架和一起使用框架的好處。

 



 

iBATIS 的優點

iBATIS 優於其他一些 OR 映射工具的優點是:

  • iBATIS 沒有使用它自己的專用查詢語言,它只使用 SQL。一些 OR 映射工具(比如 Hibernate)除了使用 SQL 之外還使用它們自己的查詢語言。
  • 所 有想要執行的查詢和更新都是使用 SQL 編寫的(並存儲在 .xml 文件中)。一些人可能認爲這是一個缺點,因此想把數據庫從他們那裏完全抽離出來,以避免需要寫入任何 SQL 代碼。這也正是許多開發人員喜歡 Hibernate 的一個原因。但您可能更喜歡能夠在訪問對象時更好地控制具體將執行哪種 SQL,而不是願意以某種依賴於基礎 OR 映射框架的方式未曾預料地爲您生成它。您可以根據數據庫管理員 (DBA) 的建議,或者根據關係數據庫管理系統 (RDBMS) 中提供的工具所提供的訪問計劃或查詢優化器來調優查詢或其他語句。直接訪問爲這一層編寫的 SQL 的另一個優點是可以利用數據庫所提供的任何專用 SQL。
  • iBATIS 易於使用。
  • 該項目有大量文件可以證明。
  • 它 沒有外部依賴性。其他一些 OR 映射框架隨同裝載了 15 到 20 個 .jar 文件,並依賴於這些文件的特定版本來運行框架。您不需要或者也不想在開發應用程序時遇到這類頭疼問題,因此使用沒有任何外部依賴性的 iBATIS 實際上是一大優點。(注意,一些可選配置允許使用外部連接工具或字節代碼增強之類的東西,但這些並不是必需的。)

現在是時間深入研究一些更特殊的 iBATIS 概念和語義,這些最終會將引導我們到一些編碼和示例。

 

BATIS Data Mapper 的語義

本教程的剩餘部分以近乎專有的方式查看 Data Mapper 框架(第 2 部分將深入介紹 DAO 框架)。這一小節將介紹 Data Mapper 的語義。

Mapped Statement

Data Mapper 的核心功能是圍繞 Mapped Statement 進行的。Mapped Statement 可以擁有稱爲 Parameter Map(基本上用於數據輸入)和 Result Map(數據輸出)的框架。因此 Mapped Statement 實質上是一個 XML 元素,該元素包含負責執行某些操作並將輸入/輸出參數映射到 Java 對象的 SQL 語句。清單 3 顯示了一個簡單的來自 JPetStore 演示版的 SQL Mapped Statement(請參閱參考資料 ,獲得到該下載的鏈接)。


清單 3. 一個簡單的 SQL Mapped Statement

<select id="getUsernameList" 
resultClass="string"
parameterClass="account">
select USERNAME as value from SIGNON
</select>

 

清單 3 中的 Mapped Statement 負責查詢 SIGNON 表中的 USERNAME 列的所有值。有幾種不同類型的 Mapped Statement。正如您所看到的,此特殊 Mapped Statement 是一個 <select> 。除了 <select> 之外,還可以在使用 iBATIS 框架時使用 <statement><insert><update><delete><procedure> Mapped Statement 元素。iBATIS 文檔更詳細地介紹了每個元素(請參閱參考資料 ,獲得到 iBATIS 的 Web 站點的鏈接)。

 



 

Parameter Map 和內聯參數

iBATIS 框架中的 Parameter Map 爲 Mapped Statement 提供數據輸入參數。Parameter Map 不常被使用並且是自發地使用(通常使用內聯參數 ),但清單 4 顯示了一個它們如何工作的示例,其中有一個來自文檔的示例 Parameter Map 和 Mapped Statement。


清單 4. iBATIS 框架中的 Parameter Map

<parameterMap id="insert-product-param" class="com.domain.Product">
<parameter property="id" jdbcType="NUMERIC"
javaType="int" nullValue="-9999999"/>
<parameter property="description" jdbcType="VARCHAR"
nullValue="NO_ENTRY"/>
</parameterMap>

<statement id="insertProduct" parameterMap="insert-product-param">
insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (?,?);
</statement>

 

您可以看到,清單 4 中的 Mapped Statement 根據名稱引用 Parameter Map,它包含兩個佔位符問號。(您將認識這些佔位符,以 JDBC PreparedStatement 的標準佔位符的形式。)它將從 Parameter Map 中獲得的值按它們被定義的順序應用於這些佔位符。

清單 4 中的 Parameter Map 定義了 com.domain.Product 類的 id 屬性 getId() ,將它映射到使用此 Parameter Map 的任何 Mapped Statement 的第一個佔位符(問號)。它繼續(使用下一個參數元素)聲明 com.domain.Product 類的 description 屬性 getDescription() ,將它映射到使用 Parameter Map 的任何 Mapped Statement 中的第二個佔位符(問號)。在 parameterMap 中,parameter 元素的顯示順序與將它們應用於使用 parameterMap 的 Mapped Statement 中的佔位符問號的順序相同。

更常見的是使用內聯參數映射輸入參數(參見清單 5 )。


清單 5. 內聯參數

<statement id="insertProduct" parameterClass="com.domain.Product">
insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)
values (#id#, #description#);
</statement>

 

此語法使用 com.domain.Product 類中的 getId() 返回的值替換 #id# ,而 #description#com.domain.Product 類的 getDescription() 返回的值替換。您可以查看 iBATIS 文檔,瞭解如何指定 null 值。

 



 

Result Map

Result Map 類似於 Parameter Map,但它用於輸出。Result Map 允許您定義將 Mapped Statements(通常是一些查詢)映射回 Java 對象的方式。清單 6 提供了來自 iBATIS 文檔的一個示例的快速查看。


清單 6. Result Map

<resultMap id="get-product-result" class="com.domain.Product">
<result property="id" column="PRD_ID"/>
<result property="description" column="PRD_DESCRIPTION"/>
</resultMap>

<statement id="getProduct" resultMap="get-product-result">
select * from PRODUCT
</statement>

 

您可以看到,具有 getProductid 的 Mapped Statement 明確地引用 Result Map 的授權 get-product-result ,告訴 Mapped Statement 將 PRD_ID 數據庫列映射到 com.domain.Product 類的 JAVA id 屬性,還聲明將 PRD_DESCRIPTION 數據庫列映射到 com.domain.Product 類的 JAVA description 屬性。

我總是喜歡指定我將要選擇的具體列,而不是使用(比如說)SELECT * FROM

 



 

TransactionManager

Data Mapper 框架中的 TransactionManager 元素允許在給定配置的情況下按您希望的對事務服務進行配置。此元素的當前受支持類型是:

  • JDBC - JDBC 事務管理器通過 java.sql.Connection 接口的 commit()rollback() 方法內部控制事務。
  • JTA - 使用一個全局 Java Transaction API (JTA) 事務,並要求 UserTransaction 通過 Java Naming and Directory Interface (JNDI) 或其他任何方法變得可用。
  • EXTERNAL - 用戶可以自己管理事務。對於必須自己以任何方式管理所有事務的非事務性數據而言,這是一個不錯的選擇。

此教程系列的第 3 部分將更詳細地查看這些事務。

配置 Derby 和 iBATIS

這一節將介紹設置基本 Derby 和 iBATIS 配置並使其運行需要做的所有事情。(正如前面所提到的,本教程將介紹 Data Mapper 框架並保存 Data Access Object 配置,將它們用於第 2 部分。)

JAR 文件

將 Apache Derby 和 iBATIS 放在一起使用的最重要的一件事是減少依賴性。在這裏,您所需要的東西是運行 Derby 的 derby.jar 文件,以及 ibatis-common-2.jar 和 ibatis-sqlmap-2.jar 文件。(如果正在使用 DAO 框架,那麼還需要 ibatis-dao-2.jar 文件,但本教程中沒有介紹該文件。)

注意,如果想利用 iBATIS 的一些額外的功能,比如字節代碼增強或集中式/分佈式緩存,那麼還需要包含 iBATIS 使用的庫(在這裏分別是 CGLIB 和 OS Cache)。這些額外的組件通常是不必要的。

 



 

配置文件

iBATIS 很少要求設置配置文件並運行它們。Data Mapper 框架需要一個 XML 配置文件(通常稱爲 sql-map-config.xml),該文件定義了與事務管理有關的項,以及如何連接到數據庫。指定包含 Mapped Statements、Result Map 等事項的 .xml 文件列表也是在這裏進行的。快速瀏覽一下將在本教程的簡單示例中使用的 sql-map-config.xml 文件(參見清單 7 )。


清單 7. sql-map-config.xml

<!DOCTYPE sqlMapConfig PUBLIC
"-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

<properties resource="properties/database.properties"/>

<settings cacheModelsEnabled="true" enhancementEnabled="false"
maxSessions="64" maxTransactions="8" maxRequests="128"/>

<transactionManager type="JDBC">
<dataSource type="SIMPLE">
<property value="${driver}" name="JDBC.Driver"/>
<property value="${url}" name="JDBC.ConnectionURL"/>
<property value="${username}" name="JDBC.Username"/>
<property value="${password}" name="JDBC.Password"/>
<property value="15" name="Pool.MaximumActiveConnections"/>
<property value="15" name="Pool.MaximumIdleConnections"/>
<property value="1000" name="Pool.MaximumWait"/>
</dataSource>
</transactionManager>

<sqlMap resource="net/humandoing/invoicing/domain/sql/Sequence.xml"/>
<sqlMap resource="net/humandoing/invoicing/domain/sql/Product.xml"/>
</sqlMapConfig>

 

清單 7 中,只有一個描述映射的 .xml 文件,在這裏該文件是 Product.xml。通常,將在幾個文件中定義此信息,然後每個域對象大致分到一個 .xml 文件。此外,要注意 XML 文件引用數據庫屬性文件的方式,該文件包含如何連接到數據庫的信息。清單 8 顯示了一個示例 database.properties 文件。


清單 8. 一個 database.properties 文件

####################################
# Database Connectivity Properties
####################################

driver=org.apache.derby.jdbc.EmbeddedDriver
url=jdbc:derby:c:/temp/ibatis
username=
password=

 

在這裏,只提供了 iBATIS 的嵌入式 Derby 驅動程序的完全限定名稱以及一個有效的 JDBC URL。不需要指定用戶名和口令,因爲在這個示例中沒有涉及安全性。

除了清單 7 中的配置文件外,Data Mapper 框架惟一需要的是任何一種爲描述數據庫查詢以及對象與數據庫之間的映射方式而定義的 .xml 文件。接下來的小節將討論用於示例應用程序的 Product.xml 文件。

儘管在本教程中不會使用到,但 DAO 框架仍然需要一個簡單的 .xml 配置文件(通常稱爲 dao.xml),幷包含一個項列表,這些項類似於 Data Mapper 配置中的那些項。這一節中包含一些事務管理信息以及 DAO 接口與實現所組成的對的列表(本教程系列的第 2 部分將更詳細地討論這些)。

 



 

爲 Derby 設置 iBATIS

因爲將使用 Derby 的嵌入式模式,且 iBATIS 抽象了所有數據庫訪問,所以只需要向正確的驅動程序和正確的數據庫 URL 提供 iBATIS 即可。iBATIS 啓動數據庫,然後在任何對 iBATIS 框架進行特定於數據庫的調用時提供對數據庫的訪問。

完成這一簡單設置之後,就爲使用 Data Mapper 框架構建一個簡單的示例應用程序做好了準備。

測試 Derby 和 iBATIS

當 您完成本教程系列的第 1 部分中的操作時,將在第 2 部分和第 3 部分中使用 JPetStore 應用程序。JPetStore 應用程序是一個示例 iBATIS 應用程序,可以從 iBATIS 框架中下載它。如果想獲得一些額外的知識或想了解一下 iBATIS,可從 iBATIS 的 Web 站點下載它(請參閱參考資料 來獲得鏈接)。

現在,您已經瞭解了 iBATIS 的一些基礎知識和它的一些概念,因此可以在一個小的示例中好好運用一下。在這一節中,將創建一個簡單的 Product 類和一個 Sequence 類。可以將 Sequence 類用作定義產品的惟一鍵的主鍵生成器。接下來將帶領您一個示例組件接一個示例組件地進行查看,在這一小節的最後,會將這些示例組件組合在一起。

定義對象

首先,定義您想一直用於數據的 Java 對象。這裏沒什麼特別之處,因爲 iBATIS 不要求擴展任何超類或實現任何接口。清單 9 定義了 Sequence 類。


清單 9. Sequence 類

public class Sequence {
private String sequenceName;
private int nextId;

public Sequence(String sequenceName, int nextId) {
this.nextId = nextId;
this.sequenceName = sequenceName;
}

public Sequence() {
}

public int getNextId() {
return nextId;
}

public void setNextId(int nextId) {
this.nextId = nextId;
}

public String getSequenceName() {
return sequenceName;
}

public void setSequenceName(String sequenceName) {
this.sequenceName = sequenceName;
}
}

 

清單 10 顯示了 Product 類。


清單 10. Product 類

public class Product {
private int productId;
private String productName;
private String productDesc;
private int quantity;

public Product(int productId, String productName,
String productDesc,int quantity) {
this.productDesc = productDesc;
this.productId = productId;
this.productName = productName;
this.quantity = quantity;
}

public Product() {
}

public int getProductId() {
return productId;
}

public void setProductId(int productId) {
this.productId = productId;
}

public String getProductName() {
return productName;
}

public void setProductName(String productName) {
this.productName = productName;
}
//...
}

 

正如您可以看到的,這兩個類都只是具有 getter/setter 方法和少數成員的普通 JavaBeans。因爲想要這些映射到數據庫的某些表的類,所以現在要定義一些數據庫表。

 



 

定義表

您需要一個表來存儲產品,還需要一個從中獲得產品並增加產品序列的另一個表,可將該序列用作主鍵。清單 11 顯示了 Derby 很友好地爲您維護的數據模型。


清單 11. 數據模型

CREATE TABLE SEQUENCE
(
SEQUENCE_NAME VARCHAR(32) NOT NULL,
NEXT_ID INTEGER NOT NULL,
CONSTRAINT SEQ_PK PRIMARY KEY (SEQUENCE_NAME)
);

CREATE TABLE PRODUCT (
PRODUCT_ID INTEGER,
PRODUCT_NAME VARCHAR(128),
PRODUCT_DESC VARCHAR(512),
QUANTITY INTEGER,
CONSTRAINT PROD_PK PRIMARY KEY (PRODUCT_ID)
);


INSERT INTO SEQUENCE (SEQUENCE_NAME, NEXT_ID)
VALUES ('ProductSeq', 1000);

 

現在有了一個 SEQUENCE 表,可從該表中選擇產品並增加產品序列,生成 PRODUCT 表的主鍵。您已經在 SEQUENCE 表中插入了一行,並且將從產品序列 1000 開始操作。您還有一個 PRODUCT 表,該表包含描述某一產品的一些典型屬性(但並沒有包含所有屬性)的少數列。

 



 

創建 SQL Map

現在需要創建描述您想要在 ProductSequence 對象上執行的數據庫操作的 SQL Map。這些數據庫操作通常包括插入、查詢、更新和刪除。

清單 12 顯示了用於 Product 類的 SQL Map。


清單 12. 用於 Product 類的 SQL Map

<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="Product">

<typeAlias alias="product"
type="net.humandoing.invoicing.domain.Product"/>

<resultMap id="productResult" class="product">
<result property="productId" column="PRODUCT_ID"/>
<result property="productName" column="PRODUCT_NAME"/>
<result property="productDesc" column="PRODUCT_DESC"/>
<result property="quantity" column="QUANTITY"/>
</resultMap>

<update id="updateProduct" parameterClass="product">
update PRODUCT set PRODUCT_NAME = #productName#,
PRODUCT_DESC = #productDesc#,
QUANTITY = #quantity# where
PRODUCT_ID = #productId#
</update>

<select id="getProduct" resultMap="productResult"
parameterClass="product">
select PRODUCT_ID, PRODUCT_NAME, PRODUCT_DESC, QUANTITY
from PRODUCT where PRODUCT_ID = #productId#
</select>

<insert id="insertProduct" parameterClass="product">
insert into PRODUCT (product_id, product_name, product_desc, quantity)
values (#productId#, #productName#, #productDesc#, #quantity#)
</insert>

</sqlMap>

 

注意 typeAlias 元素。它只允許通過更短的別名(在這裏是 product )而不是完全限定類名稱來引用類。

清單 12 中還可以看到有一個 resultMap 元素,該元素描述您想要將通過執行某一查詢獲得的將 ResultSet 映射到 Product 對象的方式。這一特殊的 resultMap 將數據庫中的 PRODUCT_ID 列映射到 Product 類的 productId 屬性,並將數據庫中的 PRODUCT_NAME 列映射到 Product 類的 productName 屬性,依此類推。

現在來快速查看一下用於 Sequence 類的 SQL Map,如清單 13 中所示。


清單 13. 用於 Sequence 類的 SQL Map

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">

<sqlMap namespace="Sequence">

<typeAlias alias="sequence"
type="net.humandoing.invoicing.domain.Sequence"/>

<resultMap id="sequenceResult" class="sequence">
<result property="sequenceName" column="SEQUENCE_NAME"/>
<result property="nextId" column="NEXT_ID"/>
</resultMap>

<select id="getSequence" resultMap="sequenceResult"
parameterClass="sequence">
select SEQUENCE_NAME, NEXT_ID from SEQUENCE
where SEQUENCE_NAME = #sequenceName#
</select>

<update id="updateSequence" parameterClass="sequence">
update SEQUENCE set NEXT_ID = #nextId#
where SEQUENCE_NAME = #sequenceName#
</update>

</sqlMap>

 

這裏有兩個 Mapped Statement:一個用來獲得序列,一個用來更新序列。還有一個 resultMap 元素,該元素描述如何將 SEQUENCE 表列映射到 Sequence Java 對象。

 



 

測試代碼

爲了讓一切順利,所有測試都作爲 Ant build 文件的少數目標包含在內。因此可以通過執行這些目標來運行測試。在運行測試之前,要查看一下 sql-map-config.xml 文件,該文件將初始化 Data Mapper 框架,以便使用其 sql-map-config.xml 文件(參見清單 14 )。


清單 14. sql-map-config.xml 文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

<properties resource="properties/database.properties"/>

<settings cacheModelsEnabled="true" enhancementEnabled="false"
maxSessions="64" maxTransactions="8" maxRequests="128"/>

<transactionManager type="JDBC">
<dataSource type="SIMPLE">
<property value="${driver}" name="JDBC.Driver"/>
<property value="${url}" name="JDBC.ConnectionURL"/>
<property value="${username}" name="JDBC.Username"/>
<property value="${password}" name="JDBC.Password"/>
<property value="15" name="Pool.MaximumActiveConnections"/>
<property value="15" name="Pool.MaximumIdleConnections"/>
<property value="1000" name="Pool.MaximumWait"/>
</dataSource>
</transactionManager>

<sqlMap resource="net/humandoing/invoicing/domain/sql/Sequence.xml"/>
<sqlMap resource="net/humandoing/invoicing/domain/sql/Product.xml"/>

</sqlMapConfig>

 

該配置簡單而又直接。iBATIS 文檔有少數一些例外示例,該文檔更詳細地描述了配置元素。主要需要注意的是,您將從位於 properties/database.properties(相對於類路徑的根路徑)的文件中獲得數據庫連接信息,還要注意的是通知 Data Mapper 您將加載兩個不同的 SQL Map:SequenceProduct

清單 15 顯示了獲得已啓動的 Data Mapper 框架所需的少數幾行 Java 源代碼(從 Test 類中獲得)。注意,大多數代碼由異常處理組成。


清單 15. 獲得已啓動的 Data Mapper 框架所涉及的 Java 源代碼

private static SqlMapClient dataMapper = null;



//...

Reader reader = null;
try {
reader = Resources.getResourceAsReader(
"net/humandoing/invoicing/domain/sql/sql-map-config.xml");
dataMapper = SqlMapClientBuilder.buildSqlMapClient(reader);
} catch (Exception e) {
e.printStackTrace();
}

 

清單 15 中一些重要的位是用粗體顯示的。Reader 只是一個使用 Resources 實用程序類的 java.io.Reader ,它使文件更易於爲您所用,該實用程序類是隨 iBATIS 一起提供的,用於從類路徑中獲得 sql-map-config.xml。

SqlMapClient 實例用於長期存在的對象(可能用於應用程序的整個生命週期),因此可能需要一個用於此實例的某個地方的靜態初始化器 (static initializer),然後允許通過靜態 getInstance() 方法類型或通過將實例綁定到 JNDI 中來訪問該實例。

現在來查看來自與 Data Mapper 框架進行交互的 Test 類的其他少數代碼片段,然後查看一些屏幕捕獲,其中包括來自 Ant 測試目標的輸出。

以下是一個用於 Sequence 的查詢:

Sequence sequence = new Sequence("ProductSeq", -1);
sequence = (Sequence)
dataMapper.queryForObject("getSequence", sequence);

這就是該查詢,它使用序列名 ProductSeq 創建了一個 Sequence 對象。如果您記得 Mapped Statement getSequence (來自 Sequence.xml 文件),那麼或許您會記得 SELECT 語句在 SEQUENCE_NAME 的基礎上執行了一個查詢。在這種情況下,iBATIS 框架將接管控制權,對 Derby 數據庫執行以下 SQL 語句:

select SEQUENCE_NAME, NEXT_ID from SEQUENCE
where SEQUENCE_NAME = "ProductSeq"

在執行上述代碼之後,您可能想保留返回的序列值,因爲要用它作爲 Derby 數據庫中創建的新產品的主鍵。或許您還想通過增加 NEXT_ID 列來更新序列(參見清單 16 )。


清單 16. 增加 NEXT_ID 列

int nextId = sequence.getNextId();

//Update the sequence by incrementing the NEXT_ID
//column.
sequence.setNextId(sequence.getNextId() + 1);
dataMapper.update("updateSequence", sequence);

 

在這裏,已經將下一個有效 ID 保存到 nextId 變量中,然後增加該值並請求 Data Mapper 框架更新 Derby 中的記錄。現在要創建一個產品,如清單 17 中所示。


清單 17. 創建一個產品

Product product = new Product(nextId, 
"iBATIS Sandwich",
"A Yummy Sandwich",
24);

product = (Product) dataMapper.insert("insertProduct", product);

 

瞧!現在有了一個也保存在該數據庫中的產品。最後但非最不重要的是,執行一個查詢確保該產品保存在數據庫中。畢竟編程人員都是一些懷疑論者。任何易於使用的數據映射框架幾乎都是看起來很好,但實際並非如此。

Product queryProd = new Product();
queryProd.setProductId(nextId);
queryProd = (Product) dataMapper.queryForObject("getProduct", queryProd);

在此查詢中,創建了一個新的 Product 對象並設置 productId (將它設置爲剛纔插入的產品的值)。然後繼續請求 Data Mapper 框架使用 getProduct 的 ID 執行 Mapped Statement,它返回一個完全填充的 Product 對象,該對象是從 Derby 數據庫中查詢獲得的。

現在來快速查看如何可以自己運行這些測試中的一些測試。

 


 

運行測試

要做的第一件事是創建 Derby 數據庫中需要的表。該示例中包含一個用於該操作的 Ant 目標。在終端窗口或 IDE 中運行 ant create-database (確保當前目錄位於項目的根目錄上),您將獲得與圖 1 中所示輸出類似的東西。


圖 1. 來自 create-database 目標的 Ant 輸出

BUILD SUCCESSFUL —— 這是每個人都喜歡看到的。現在已經創建好了表,可以快速查詢 PRODUCT 表,查看裏面是否有東西。運行 ant get-products ,它將查詢 Derby 數據庫的 PRODUCT 表中的所有行。您應該接收到一些類似圖 2 中所示的輸出。


圖 2. 來自 get-products 目標的 Ant 輸出

在這裏所能看到的就是數據庫中沒有任何產品;可以看到一些列標題,但沒有產品。現在運行一個測試,該測試獲得一個 Sequence 、更新它、創建一個 Product 並隨後查詢該產品。用於此操作的 Ant 目標是 ant run-test圖 3 中顯示了結果。


圖 3. 來自 run-test 目標的 Ant 輸出

您已經查詢了名爲 ProductSeqSequence ,它有一個來自數據庫的爲 1000 的 NEXT_ID 。然後您可以創建一個 Product圖 3 中看到的輸出是在已將產品插入數據庫之後使用 Data Mapper 框架查詢該產品所獲得的結果。您可以根據自己的需要多次運行 ant run-test 目標。它會繼續將 iBATIS Sandwiches 插入 Derby 數據庫並繼續增加序列。

最後,通過再次運行 ant get-products 目標並查詢數據庫來獲得所有產品行,可以打消您的疑慮。可以在圖 4 中查看結果。


圖 4. 插入某一產品後來自 get-products 目標的輸出

圖 4 中可以看到,已經通過 iBATIS Data Mapper 框架將 iBATIS Sandwich 成功添加到 Derby 數據庫中。

發佈了13 篇原創文章 · 獲贊 0 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章