成都心情

  BlogJava :: 首页 ::  :: 联系 :: 聚合  :: 管理 ::
  98 随笔 :: 2 文章 :: 501 评论 :: 1 Trackbacks

     让我们重回到车辆管理系统和张三的故事中。      

    iBATIS SQL Maps 的世界里也存在 one-to-many many-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>

 

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 产生 冲突,放进 <![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 Class keyProperty="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>

 

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();
  }
 }
}

 

程序和 Hibernate 写法差不多,我感觉甚至比 Hibernate 更简单。我可以显示的进行 insert 操作,符合传统 JDBC 编程习惯。 iBATIS SQL Maps 支持自动事务处理,可以不用写明 startTransaction commitTransaction 。但如果 People insert 操作成功,而 AutoInfo insert 操作失败,就破坏了两次 insert 操作的原子性。最后 endTransaction 包含异常情况下的回滚事务和关闭连接池连接两种功能。




请注意!引用、转贴本文应注明原作者:Rosen Jiang 以及出处:http://www.blogjava.net/rosen

posted on 2005-08-12 14:10 Rosen 阅读(2513) 评论(0)  编辑  收藏 所属分类: O/R Mapping

只有注册用户登录后才能发表评论。


网站导航: