IBATIS SQLMap詳解
在 iBATIS SQL Maps 的世界里也存在 one-to-many、many-to-one 的關系,想必你已經對這些概念駕輕就熟了。好!還是每個 People 對應多條 AutoInfo 信息。
本系列文章第一部分提到過 iBATIS SQL Maps 的映射文件個數可以人為設定,但是,把一組有共性的操作放在一起是首選策略。下面我們看看為張三首次買車所生成的映射文件是怎樣的:
PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd"> insert into people (name, address) values (#name#, #address#) ]]> select last_insert_id(); ]]> insert into auto_info (license_plate, owner_no) VALUES (#licensePlate#, #ownerNo.id#) ]]>
PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd"> insert into people (name, address) values (#name#, #address#) ]]> select last_insert_id(); ]]> insert into auto_info (license_plate, owner_no) VALUES (#licensePlate#, #ownerNo.id#) ]]> |
sqlMap
sqlMap 元素擁有屬性 namespace="…",定義了該 XML 文件命名空間。如果你在配置文件 SqlMapConfig.xml 中指定了 settings 元素的屬性 useStatementNamespaces="true",那么就可以按照命名空間的方式訪問 Mapped statement,比如 namespace=" AutoMag",相應 Java 代碼:sqlMap.insert("AutoMag.insertPeople",people)。這樣做是為了防止不同映射文件中出現同名 Mapped statement 而產生沖突。
什么是 Mapped statement ?
Mapped statement
iBATIS SQL Maps 的核心概念就是 Mapped statement!Mapped Statement 可以使用任意的 SQL 語句,利用 POJO、原始變量及其 Wrapper Class 作為輸入(parameter class)和輸出(result class)。
Mapped Statement 包含以下幾種類型:
insert 對應數據庫的 insert 操作,該操作返回本次操作插入記錄的主鍵值。
select 對應數據庫的 select 操作,該操作返回特定的 POJO 或 對象。
update 對應數據庫的 update 操作,該操作返回被更新的記錄個數。
delete 對應數據庫的 delete 操作,該操作返回被刪除的記錄個數。
procedure 對應數據庫存儲過程。
statement 類型最為通用,可以代替以上所有的類型。但由于缺乏操作直觀性故不推薦。
insert id="insertPeople" parameterClass="bo.People"
定義了 insert 類型的 Mapped Statement。屬性 id="insertPeople" 定義操作名稱,parameterClass="bo.People" 定義傳入參數為 People 對象實例,框架可確保其屬性持久化到數據庫相應字段中。由于 SQL 語句會包含“<>”這樣的符號,容易和 XML 產生沖突,放進 ……]]> 區域就可避免。insert into people (name, address) values (#name#, #address#),是一條普通的 SQL 語句,“#name#、#address#”利用 Java 反射機制訪問 People 對象實例的相應屬性。
selectKey resultClass="java.lang.Integer" keyProperty="id"
iBATIS SQL Maps 通過
以下是 Oracle 和 SQL Server 主鍵生成方法:
< !- Oracle -> <insert id="insertProduct-ORACLE" parameterClass="com.domain.Product"> <selectKey resultClass="int" keyProperty="id" > SELECT STOCKIDSEQUENCE.NEXTVAL AS ID FROM DUAL </selectKey> INSERT INTO PRODUCT (PRD_ID,PRD_DESCRIPTION) values (#id#,#description#) </insert>
Microsoft SQL Server -> <insert id="insertProduct-MS-SQL" parameterClass="com.domain.Product"> insert into PRODUCT (PRD_DESCRIPTION) values (#description#) <selectKey resultClass="int" keyProperty="id" > SELECT @@IDENTITY AS ID </selectKey> </insert>
< !- Oracle -> <insert id="insertProduct-ORACLE" parameterClass="com.domain.Product"> <selectKey resultClass="int" keyProperty="id" > SELECT STOCKIDSEQUENCE.NEXTVAL AS ID FROM DUAL </selectKey> insert into PRODUCT (PRD_ID,PRD_DESCRIPTION) values (#id#,#description#) </insert>
Microsoft SQL Server -> <insert id="insertProduct-MS-SQL" parameterClass="com.domain.Product"> insert into PRODUCT (PRD_DESCRIPTION) values (#description#) <selectKey resultClass="int" keyProperty="id" > SELECT @@IDENTITY AS ID </selectKey> </insert> insert into auto_info (license_plate, owner_no) VALUES (#licensePlate#, #ownerNo.id#) |
在插入了 people 記錄后,要為 auto_info 插入記錄。基本原則和之前遇到過的一樣,只是”owner_no”這個字段值由 AutoInfo 對象屬性”ownerNo”獲得,該屬性類型為 People。這是由于我沿用了 Hibernate 產生的 POJO,如果你愿意,完全可以把”ownerNo”替換為 Integer 類型。
編程中幾個關鍵對象:
1. com.ibatis.common.resources.Resources 對象負責從 XML 得到 java.io.Reader 抽象類的實例,供工廠方法調用。
2. com.ibatis.sqlmap.client.SqlMapClientBuilder 構造 SqlMapClient 實例。
3. com.ibatis.sqlmap.client.SqlMapClient 是 iBATIS SQL Maps 核心組件,可以說我們的編程工作都是圍繞著它展開。
形成的 one-to-many 保存如下:
package test; import java.io.Reader; import com.ibatis.sqlmap.client.*; import com.ibatis.common.resources.*; import bo.*; public class AutoMag { private Reader reader; private SqlMapClient sqlMap; private String resource = "SqlMapConfig.xml"; public void insertPeople() throws Exception{ try{ reader = Resources.getResourceAsReader(resource); sqlMap=SqlMapClientBuilder.buildSqlMapClient(reader); sqlMap.startTransaction(); People people=new People(); people.setName("張三"); people.setAddress("中國"); sqlMap.insert("insertPeople",people); AutoInfo autoInfo=new AutoInfo(); autoInfo.setLicensePlate("A00001"); autoInfo.setOwnerNo(people); sqlMap.insert("insertAutoInfo",autoInfo); sqlMap.commitTransaction(); }finally{ sqlMap.endTransaction(); } } } package test; import java.io.Reader; import com.ibatis.sqlmap.client.*; import com.ibatis.common.resources.*; import bo.*; public class AutoMag { private Reader reader; private SqlMapClient sqlMap; private String resource = "SqlMapConfig.xml"; public void insertPeople() throws Exception{ try{ reader = Resources.getResourceAsReader(resource); sqlMap=SqlMapClientBuilder.buildSqlMapClient(reader); sqlMap.startTransaction(); People people=new People(); people.setName("張三"); people.setAddress("中國"); sqlMap.insert("insertPeople",people); AutoInfo autoInfo=new AutoInfo(); autoInfo.setLicensePlate("A00001"); autoInfo.setOwnerNo(people); sqlMap.insert("insertAutoInfo",autoInfo); sqlMap.commitTransaction(); }finally{ sqlMap.endTransaction(); } } } |
程序和 Hibernate 寫法差不多,我感覺甚至比 Hibernate 更簡單。我可以顯示的進行 insert 操作,符合傳統 JDBC 編程習慣。iBATIS SQL Maps 支持自動事務處理,可以不用寫明 startTransaction、commitTransaction。但如果 People insert 操作成功,而 AutoInfo insert 操作失敗,就破壞了兩次 insert 操作的原子性。最后 endTransaction 包含異常情況下的回滾事務和關閉連接池連接兩種功能。
posted on 2005-11-09 19:17 船夫 閱讀(9926) 評論(6) 編輯 收藏 所屬分類: java技術