5.1 更新數據的基石?
在第4章中,您已經學習了所有的語句類型和基本查詢相關的部分API。這里我們再來看一下執行非查詢語句常用的API,然后回顧一下更新數據庫相關的語句類型。
5.1.1 非查詢SQL語句相關的API
我們把更新數據庫的一些“高級”的技術保留在下章中,這里就僅僅看一下insert,update,delete的基本內容——更新數據庫時最常用的三個方法。不過,現在只給出簡單的介紹,暫時已經夠用了,它們的詳細內容將在本章稍后給出。
Insert方法
也許您已猜到,Insert方法用于執行那些對應于SQL中INSERT語句的映射語句:
Insert方法接受兩個參數:映射語句的名稱(id)和作為參數的對象,后者包含了要插入到數據庫的數據。
在更新數據庫所用的三個方法中,Insert方法與另兩個不同,它返回的是一個object(見5.2.3節)。
Update方法
Update方法用于執行那些對應于SQL中UPDATE語句的映射語句:
與Insert方法一樣,Update方法也接受兩個參數:映射語句的名稱(id)和作為參數的對象。返回值則是執行UPDATE語句所影響的行數。
Delete方法
sql查詢語句執行順序,
Delete方法與Update方法幾乎一樣,只是它是用來執行DELETE語句的:
5.1.2 非查詢語句
表5.1是第4章的表4.1的子集。
語句類型 | 特性 | 子元素 | 用途 where語句執行順序。 | 詳細內容參考 |
<insert> | id parameterClass parameterMap | 所有動態元素<selectKey> <generate> | 插入數據 | 5.2節; |
<update> | id | 所有動態元素 | 更新數據 | 5.3節; |
<delete> | id | 所有動態元素 | 刪除數據 | 5.3節; |
<procedure> | id sql取唯一記錄、 | 所有動態元素 | 執行存儲過程 | 5.5節; |
<statement> | id parameterClass resultClass listClass parameterMap resultMap cacheModel | 所有動態元素 | 可以包含任意類型的語句,幾乎無所不能 | 6.3.1節; |
譯注:在iBATIS.NET的DataMapper1.6.1版本中,還有另外兩個與語句相關的元素:<sql>和<include>,能給我們帶來更多方便,詳細內容請參看iBATIS官方文檔。
5.2 插入數據
向數據庫中插入數據與查詢數據不盡相同,但過程卻很相似。不管我們使用的是內聯參數還是外部參數映射(這兩種參數方式都在第4章有詳細描述),在執行任何映射語句時它們的工作原理都是類似的。
5.2.1 使用內聯參數
使用內聯參數,創建映射語句的過程會很快。這里時一個使用內聯參數的<insert>類型語句的例子:
????insert?into?account?(
????accountId,
????username,?password,
????memberSince,
????firstName,?lastName,
????address1,?address2,
????city,?state,?postalCode,
????country,?version)?
????values?(
????#accountId:NUMBER#,
????#username:VARCHAR#,?#password:VARCHAR#,
????#memberSince:TIMESTAMP#,
????#firstName:VARCHAR#,?#lastName:VARCHAR#,
????#address1:VARCHAR#,?#address2:VARCHAR#,
????#city:VARCHAR#,?#state:VARCHAR#,?#postalCode:VARCHAR#,
????#country:VARCHAR#,?#version:NUMBER#
????)
</insert>
這是映射語句,執行它的代碼(在單元測試中)則可以這么寫:
account.AccountId?=?9999;
account.Username?=?"inlineins";
account.Password?=?"poohbear";
account.FirstName?=?"Inline";
account.LastName?=?"Example";
SqlMapper.Insert("Account.insertWithInlineInfo",?account);
這種方式確實有效,但是一旦程序中包含了<insert>和<update>語句的多個版本,代碼就變得冗長而且難以維護。如果不幸發生了這種情況,那么外部參數就可以幫我們簡化SQL Map文件的維護工作了。
5.2.2 使用外部參數
外部參數不僅可以提供內聯參數的功能,還能改善性能并在加載時提供更多的校驗(這意味著運行時的更少錯誤)。
這里時一個使用外部參數的<insert>語句示例,其代碼在功能上與上個例子一樣。????<parameter?property="accountId"?dbType="NUMBER"?/>
????<parameter?property="username"?dbType="VARCHAR"?/>
????<parameter?property="password"?dbType="VARCHAR"?/>
????<parameter?property="memberSince"?dbType="TIMESTAMP"?/>
????<parameter?property="firstName"?dbType="VARCHAR"?/>
????<parameter?property="lastName"?dbType="VARCHAR"?/>
????<parameter?property="address1"?dbType="VARCHAR"?/>
????<parameter?property="address2"?dbType="VARCHAR"?/>
????<parameter?property="city"?dbType="VARCHAR"?/>
????<parameter?property="state"?dbType="VARCHAR"?/>
????<parameter?property="postalCode"?dbType="VARCHAR"?/>
????<parameter?property="country"?dbType="VARCHAR"?/>
????<parameter?property="version"?dbType="NUMBER"?/>
</parameterMap>
????????
<insert?id="insertWithExternalInfo"
parameterMap="fullParameterMapExample">
????insert?into?account?(
????accountId,
????username,?password,
????memberSince
????firstName,?lastName,
????address1,?address2,
????city,?state,?postalCode,
????country,?version)?
????values?(?,?,?,?,?,?,?,?,?,?,?,?,?)
</insert>
可是看起來并沒簡單多少啊!不過如果語句多了,差別就明顯了。不僅更為簡單(因為不再需要為每個屬性指定類型),而且因為有了統一的維護點,如果要修改Parameter Map,只要修改一處即可。
例如,在傳入memberSince的每個地方,iBATIS都會自動將其作為TIMESTAMP數據庫類型來處理。過了一段時間,我們覺得DATETIME就夠了,只要修改一處——Parameter Map。
在前面的兩個例子中,執行語句的代碼是一樣的(除了語句的名稱):sqlMap.Insert("Account.insertWithExternalInfo",?account);
到這里我們可以看到,內聯參數和外部參數的區別在于可維護性和性能——外部參數對此都進行了優化。
5.2.3 自動生成的主鍵
數據庫語句怎么執行。
對于任何數據庫來說,提供唯一標識數據表中一行記錄的能力是至關重要的。幾乎所有數據庫都提供了為新添加的行自動生成主鍵的方法。這樣再操作數據庫的時候比較方便,但它也帶來了一個問題,如果我們需要知道新生成的主鍵值該怎么辦?
有的數據庫供應商是預先生成(pre-generate)主鍵的(如Oracle和PostgreSQL),有的則是事后生成(post-generate)的(如SQL Server和MySQL)。不管是哪種方式,我們都可以使用<selectKey>節點來獲取<insert>語句所產生的主鍵。下面的例子演示了這兩種方式下的做法:<insert?id="insertProduct-ORACLE"?parameterClass="product">
????<selectKey?resultClass="int"?type="pre"?property="Id"?>
????????SELECT?STOCKIDSEQUENCE.NEXTVAL?AS?VALUE?FROM?DUAL
????</selectKey>
????insert?into?PRODUCT?(PRD_ID,PRD_DESCRIPTION)?values?(#id#,#description#)
</insert>
<!--?Microsoft?SQL?Server?IDENTITY?Column?Example?-->
<insert?id="insertProduct-MS-SQL"?parameterClass="product">
????insert?into?PRODUCT?(PRD_DESCRIPTION)
????values?(#description#)
????<selectKey?resultClass="int"?type="post"?property="id"?>
????????select?@@IDENTITY?as?value
????</selectKey>
</insert>
<!--?MySQL?Example?-->
<insert?id="insertProduct-MYSQL"?parameterClass="product">
????insert?into?PRODUCT?(PRD_DESCRIPTION)
????values?(#description#)
????<selectKey?resultClass="int"?type="post"?property="id"?>
????????select?LAST_INSERT_ID()?as?value
????</selectKey>
</insert>