成都心情

Csdn 的 Blog 太难用了,忍无可忍。已搬往:http://www.blogjava.net/rosen

原创 iBATIS SQL Maps(二)收藏

新一篇: iBATIS SQL Maps(三) | 旧一篇: 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

发表于 @ 2005年01月16日 16:00:00|评论(loading...)|编辑

新一篇: iBATIS SQL Maps(三) | 旧一篇: iBATIS SQL Maps(一)

评论

#rosen 发表于2005-01-23 23:03:00  IP:
TrackBack来自《iBATIS SQL Maps(四)》

Ping Back来自:blog.csdn.net
#rosen 发表于2005-01-19 10:09:00  IP: 221.237.160.*
Dear chenjf:
对于大对象的操作正是我下一步要做的,已列入“待解决问题”。目前,我们项目中还没有这方面的需求,暂时无法回答你。
#chenjf 发表于2005-01-18 14:24:00  IP: 211.95.121.*
请教一个问题:我通过ibatis的TypeHandlerCallback接口,实现了对ORACLE数据库中CLOB字段的读写,但对BLOB字段只实现了读取功能,无法实现写入的操作,看了你的文章,觉得你应该对ibatis很熟悉,是否可以给个例子,谢谢。
#rosen 发表于2005-02-19 12:20:00  IP: 222.212.194.*
Dear chenjf:
更加完善的解决方案,可参考http://blog.csdn.net/rosen/archive/2005/02/18/293151.aspx
#ybyb14 发表于2006-12-10 17:08:46  IP: 59.60.9.*
写的不错,selectKey 这个有些看不太明白
#b2007j 发表于2007-07-31 10:25:20  IP: 123.114.70.*
最近刚好工作用到IBATIS 感谢!!
发表评论  


当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
Csdn Blog version 3.1a
Copyright © rosen