iBATIS SQL Maps(二)

    讓我們重回到車輛管理系統和張三的故事中。

    iBATIS SQL Maps 的世界裏也存在 one-to-manymany-to-one 的關係,想必你已經對這些概念駕輕就熟了。好!還是每個 People 對應多條 AutoInfo 信息。

    本系列文章第一部分提到過 iBATIS SQL Maps 的映射文件個數可以人爲設定,但是,把一組有共性的操作放在一起是首選策略。下面我們看看爲張三首次買車所生成的映射文件是怎樣的:

<?xml version="1.0" encoding="UTF-8"?>

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

<sqlMap namespace="AutoMag">

  <insert id="insertPeople" parameterClass="bo.People">
    <![CDATA[
      insert into people (name, address) values (#name#, #address#)
    ]]>
      <selectKey resultClass="java.lang.Integer" keyProperty="id">
    <![CDATA[
          select last_insert_id();
    ]]>
      </selectKey>
  </insert>
 
  <insert id="insertAutoInfo" parameterClass="bo.AutoInfo">
    <![CDATA[
      insert into auto_info (license_plate, owner_no) VALUES (#licensePlate#, #ownerNo.id#)
    ]]>
  </insert>
</sqlMap>

 

<?xml version="1.0" encoding="UTF-8"?>

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

<sqlMap namespace="AutoMag">

  <insert id="insertPeople" parameterClass="bo.People">
    <![CDATA[
      insert into people (name, address) values (#name#, #address#)
    ]]>
      <selectKey resultClass="java.lang.Integer" keyProperty="id">
    <![CDATA[
          select last_insert_id();
    ]]>
      </selectKey>
  </insert>
 
  <insert id="insertAutoInfo" parameterClass="bo.AutoInfo">
    <![CDATA[
      insert into auto_info (license_plate, owner_no) VALUES (#licensePlate#, #ownerNo.id#)
    ]]>
  </insert>
</sqlMap>

 

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 statementMapped 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 產生衝突,放進 <![CDATA[……]]> 區域就可避免。insert into people (name, address) values (#name#, #address#)是一條普通的 SQL 語句,“#name##address#”利用 Java 反射機制訪問 People 對象實例的相應屬性。

selectKey resultClass="java.lang.Integer" keyProperty="id"

iBATIS SQL Maps 通過 <insert> 元素的子元素 < selectKey> 來支持主鍵自動生成。 resultClass="java.lang.Integer" 定義返回對象爲 int Wrapper ClasskeyProperty="id" 定義了主鍵名稱。本例是 MySQL 主鍵生成方式,參考官方文檔,MySQL 的主鍵生成無需人爲來控制,也就是說可不使用 <selectKey> 而由數據庫自動處理。但我測試發現,在執行 insert 操作以後,程序沒有返回本次操作插入記錄的主鍵值。在官方論壇上也有很多用戶提出這樣的疑惑,作者的答覆是:這和 JDBC Driver 有關係。不可能把驅動一一測試吧?一勞永逸的辦法是使用 <selectKey> 元素。以下是 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 類型。

編程中幾個關鍵對象

    com.ibatis.common.resources.Resources 對象負責從 XML 得到 java.io.Reader 抽象類的實例,供工廠方法調用。

com.ibatis.sqlmap.client.SqlMapClientBuilder 構造 SqlMapClient 實例。

    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 支持自動事務處理,可以不用寫明 startTransactioncommitTransaction。但如果 People insert 操作成功,而 AutoInfo insert 操作失敗,就破壞了兩次 insert 操作的原子性。最後 endTransaction 包含異常情況下的回滾事務和關閉連接池連接兩種功能。

        

(請注意!引用、轉貼本文應註明原作者:Rosen Jiang 以及出處:http://blog.csdn.net/rosen

        

(請注意!引用、轉貼本文應註明原作者:Rosen Jiang 以及出處:http://blog.csdn.net/rosen

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章