`
sungang_1120
  • 浏览: 322744 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类

使用 ibatis 处理复杂对象数据关系的实例

阅读更多

ibatis 基本介绍

起源于 2001 年的开放源代码项目 ibatis,是一个基于 Java 的持久层框架。与 Hibernate, Toplink 等持久化框架不同,ibatis 是一个 “半自动化”的 ORM 实现。ibatis 没有对数据库结构提供了较为完整的封装,而是提供了一个从 POJO 到数据库表的全套映射机制。这使得在开发 ibatis 的时候,需要手动的编写 sql 来提过数据库与类对象之间的映射,这在给开发提供了很大的灵活性的同时,大大增加了开发的工作量。Ibatis 主要有以下的这些特性:

1. 简单性

Ibatis 是一个非常简单易用的工具包。这个简单性不仅仅体现在开发库的轻量小巧上,iBATIS 对于 Java 开发者来说也非常简单。因为它除了不用编写那么多代码外与 JDBC 的工作机制非常相像,iBATIS 就是以 XML 的形式来描述的 JDBC 代码。iBATIS 对于数据库管理员以及 SQL 程序员来 说也非常容易理解。iBATIS 配置文件几乎人人都能读懂,只要他有 SQL 编程的经验。

2. 效率与性能

iBATIS 通过一种简单的方式来配置和使用,其性能与 JDBC 相当。通过直接编写 SQL 查询,开发人员可以直接控制 SQL 语句来优化执行效率,甚至可以在其中调用存储过程,为开发人员提供了巨大的 SQL 优化空间。

3. 代码分离

在 iBATIS 中,SQL 语句在很大程度上同应用的源代码是分离 的,SQL 程序员可以按照 SQL 原本的方式来编写它,而不必担心有关 SQL 字符串连接的问题。iBATIS 提供了充分的自由,使得任何人都可以开发、观察并且修改在数据库中执行的 SQL 语句。

4. 可移植性

iBATIS 是可移植的。由于它相对简单的设计,它几乎可以用任何一种语言在任何一个平台上实现。iBATIS 支持 3 种最受欢迎的开发平台:Java、Ruby 和微软 .NET 的 C#。

常见的对象映射与实现

由于在使用 ibatis 进行项目开发中,需要根据数据库的表结构与 Java 类之间的关系写出实现的 SQL 代码,不同的关系会对应不同 SQL 实现。这些 SQL 代码将会和其他 mapping 信息一起放在 ibatis 的 SQL mapping 文件中。下面就对这些每一种映射进行详细分析并给出实现示例。

单表对象绑定与多表对象绑定

在 ibatis 中最简单的关系就是一个对象对单个表的绑定,这也是最简单的类与数据库的映射关系。在没有任何外键关系的时候,在 ibatis 中直接将类的字段对应到表的列即可:

清单 1. 单个对象表绑定的实现

  1. <typeAlias alias="Bank" type="com.example.domain.Bank"/>   
  2.      <resultMap id="getBankResult" class="Bank">   
  3.   <result property="id" column="B_ID"/>   
  4.   <result property="name" column="B_NAME"/>   
  5.   </resultMap>   
  6.     
  7.  <select id="getBankById" resultMap="getBankResult" parameterClass="string"/>   
  8.  SELECT `BANKL`.`BANKID` AS `B_ID`, `BANKL`.`NAME` AS `B_NAME`   
  9.  FROM `BANKL`   
  10.  WHERE `BANKID` = #id#   
  11.  </select/>  
<typeAlias alias="Bank" type="com.example.domain.Bank"/> 
	 <resultMap id="getBankResult" class="Bank"> 
  <result property="id" column="B_ID"/> 
  <result property="name" column="B_NAME"/> 
  </resultMap> 
  
 <select id="getBankById" resultMap="getBankResult" parameterClass="string"/> 
 SELECT `BANKL`.`BANKID` AS `B_ID`, `BANKL`.`NAME` AS `B_NAME` 
 FROM `BANKL` 
 WHERE `BANKID` = #id# 
 </select/>


在某些特殊的对象中,有的时候需要将一个对象映射到多个表中,在这个时候就需要在映射时加入对两张表的选择。因此,需要对上面的简单的 sql 进行一些改动,加入一个两张表的 join 操作,以下是示例:

清单 2. 单个对象多表绑定的实现

  1.               
  2.   
  3. <typeAlias alias="Customer" type="com.example.domain.Customer"/>   
  4.  <resultMap id="getCustomerResult" class="Customer">   
  5.    <result property="id" column="C_ID"/>   
  6.    <result property="name" column="C_NAME"/>   
  7.    <result property="birthday" column="C_BIRTHDAY"/>   
  8.    <result property="gender" column="C_GENDER"/>   
  9.    <result property="identityType" column="C_IDENTITYTYPE"/>   
  10.      <result property="identityId" column="C_IDENTITYID"/>   
  11.    <result property="consumePoint" column="C_CONSUMEPOINT"/>   
  12.    <result property="lastGetDate" column="C_LASTGETDATE"/>   
  13.      <result property="lastUseDate" column="C_LASTUSEDATE"/>   
  14.  </resultMap>   
  15. <select id="getCustomerById" resultMap="getCustomerResult" parameterClass="string"/>    
  16. SELECT   
  17. `CUMAS`.`ID` AS `C_ID`, `CUMAS`.`NAME` AS `C_NAME`, `CUMAS`.`BIRTHDAY` AS   
  18. `C_BIRTHDAY`, `CUMAS`.`GENDER` AS `C_GENDER`, `CUMAS`.`IDTYPE` AS `C_IDENTITYTYPE`,   
  19. `CUMAS`.`IDNO` AS `C_IDENTITYID`, `CUSPT`.`POINT` AS `C_CONSUMEPOINT`, `CUSPT`.`LASTGET`   
  20. AS `C_LASTGETDATE`, `CUSPT`.`LASTUSE` AS `C_LASTUSEDATE`   
  21. FROM `CUMAS`, `CUSPT` WHERE `ID` = #id# AND `CUMAS`.`ID` = `CUSPT`.`CUSID`  
  22. <select/>   
				
 
 <typeAlias alias="Customer" type="com.example.domain.Customer"/> 
  <resultMap id="getCustomerResult" class="Customer"> 
    <result property="id" column="C_ID"/> 
    <result property="name" column="C_NAME"/> 
    <result property="birthday" column="C_BIRTHDAY"/> 
    <result property="gender" column="C_GENDER"/> 
    <result property="identityType" column="C_IDENTITYTYPE"/> 
		 <result property="identityId" column="C_IDENTITYID"/> 
    <result property="consumePoint" column="C_CONSUMEPOINT"/> 
    <result property="lastGetDate" column="C_LASTGETDATE"/> 
		 <result property="lastUseDate" column="C_LASTUSEDATE"/> 
  </resultMap> 
 <select id="getCustomerById" resultMap="getCustomerResult" parameterClass="string"/>  
 SELECT 
 `CUMAS`.`ID` AS `C_ID`, `CUMAS`.`NAME` AS `C_NAME`, `CUMAS`.`BIRTHDAY` AS 
 `C_BIRTHDAY`, `CUMAS`.`GENDER` AS `C_GENDER`, `CUMAS`.`IDTYPE` AS `C_IDENTITYTYPE`, 
 `CUMAS`.`IDNO` AS `C_IDENTITYID`, `CUSPT`.`POINT` AS `C_CONSUMEPOINT`, `CUSPT`.`LASTGET` 
 AS `C_LASTGETDATE`, `CUSPT`.`LASTUSE` AS `C_LASTUSEDATE` 
 FROM `CUMAS`, `CUSPT` WHERE `ID` = #id# AND `CUMAS`.`ID` = `CUSPT`.`CUSID`
 <select/> 


在上面这个例子中,Customer 这个对象被映射到 CUMAS 与 CUSPT 两个表中,每个表中包含了一部分字段,所以在选择的时候需要将两张表 join 起来。在进行删除,修改等操作时,需要注意的是要创建两条语句并在 java code 中对两条语句都进行调用,否则会导致数据不一致的现象发生:

清单 3. 单个对象多表绑定的删除语句

  1. <delete id="deleteCustomer" parameterClass="string">   
  2.  DELETE FROM `CUMAS` WHERE `ID` = #id#      
  3.   </delete>   
  4.   <delete id="deleteCustomer2" parameterClass="string">   
  5.  DELETE FROM `CUSPT` WHERE `CUSID` = #id#      
  6.  </delete>   
<delete id="deleteCustomer" parameterClass="string"> 
 DELETE FROM `CUMAS` WHERE `ID` = #id#    
  </delete> 
  <delete id="deleteCustomer2" parameterClass="string"> 
 DELETE FROM `CUSPT` WHERE `CUSID` = #id#    
 </delete> 

单主键与多主键

在数据库中,一般需要对每条记录定义一个主键,大部分情况下采用一个自增长的 ID 来实现。这个时候有两种实现方法,第一种是用数据库自带的 id 增长功能,如何在 ibatis 中实现这种情况已在 iBatis 帮助文档中有详细说明,这里就不在赘述。第二种方法是采用类似 Toplink 中的实现方式,在 Java 中控制 ID 的增长,这种方法使用一张 sequence 表来存放所有的 id 记录,该表有两个字段,第一个为表名,第二个为当前最新的 id 值,表中的每一行对应一个自增长的 id。与该表对应的为一个 Java 的 Sequence 类与 iBatis 映射文件。在查询每个 sequence 时,通过 sequence name 将当前 id 值取出并设置到对象的 id 中。

在获取新的 sequence 时,需要注意的是对并发的控制,在同一时间只能有一个线程更新 sequence,否则将会导致主键重复。

清单 4. Sequence 的实现

  1.             Sequence 的 Java 类  
  2. public class Sequence{   
  3.    protected String name;   
  4.    protected String nextId;   
  5.    public String getName() {   
  6.      return name;   
  7.    }   
  8.    public void setName(String name) {   
  9.      this.name = name;   
  10.    }   
  11.    public String getNextId() {   
  12.      return nextId;   
  13.    }   
  14.    public void setNextId(String nextId) {   
  15.      this.nextId = nextId;   
  16.    }   
  17. }   
  18. Sequence 的 SQL 映射  
  19. <sqlMap namespace="Sequence">   
  20. <typeAlias alias="Sequence" type="com.example.Sequence"/>   
  21.  <resultMap id="getSequenceResult" class="Sequence">   
  22.    <result property="name" column="S_NAME"/>   
  23.    <result property="nextId" column="S_NEXTID"/>   
  24.  </resultMap>   
  25. <select id="getSequenceById" resultMap="getSequenceResult" parameterClass="string" >    
  26. SELECT   
  27. `SEQ`.`SEQNAME` AS `S_NAME`, `SEQ`.`SEQVALUE` AS `S_NEXTID` FROM `SEQ`   
  28. WHERE `SEQNAME` = #name#   
  29. </select>    
  30. <update id="updateSequence" parameterClass="Sequence">    
  31. UPDATE `B2CSEQ` SET `SEQVALUE`=#nextId# WHERE `SEQNAME` = #name#   
  32. </update>   
  33. </sqlMap>   
  34. 通过 Sequence 获取 ID 的方法  
  35. public static synchronized String getNextId(String name) throws SQLException {   
  36.   SqlMapSession sequenceSession=SessionManager.retrieveSession();   
  37.   ISequence sequence = (ISequence) sequenceSession.queryForObject(   
  38.        "getSequenceById", name);   
  39.   if (sequence == null) {   
  40.    throw new SQLException("Error: A null sequence was returned from the database" +   
  41.      " (could not get next "+ name + " sequence).");   
  42.   }   
  43.   String id = sequence.getNextId();   
  44.   sequence.setNextId((new BigDecimal(id).add(new BigDecimal(5))).toString());   
  45.   sequenceSession.startTransaction();   
  46.   sequenceSession.update("updateSequence", sequence);   
  47.   sequenceSession.commitTransaction();   
  48.   sequenceSession.close();   
  49.   return String.valueOf(sequence.getNextId());   
  50.  }   
				Sequence 的 Java 类
 public class Sequence{ 
    protected String name; 
    protected String nextId; 
    public String getName() { 
      return name; 
    } 
    public void setName(String name) { 
      this.name = name; 
    } 
    public String getNextId() { 
      return nextId; 
    } 
    public void setNextId(String nextId) { 
      this.nextId = nextId; 
    } 
 } 
 Sequence 的 SQL 映射
 <sqlMap namespace="Sequence"> 
 <typeAlias alias="Sequence" type="com.example.Sequence"/> 
  <resultMap id="getSequenceResult" class="Sequence"> 
    <result property="name" column="S_NAME"/> 
    <result property="nextId" column="S_NEXTID"/> 
  </resultMap> 
 <select id="getSequenceById" resultMap="getSequenceResult" parameterClass="string" >  
 SELECT 
 `SEQ`.`SEQNAME` AS `S_NAME`, `SEQ`.`SEQVALUE` AS `S_NEXTID` FROM `SEQ` 
 WHERE `SEQNAME` = #name# 
 </select>  
 <update id="updateSequence" parameterClass="Sequence">  
 UPDATE `B2CSEQ` SET `SEQVALUE`=#nextId# WHERE `SEQNAME` = #name# 
 </update> 
 </sqlMap> 
 通过 Sequence 获取 ID 的方法
 public static synchronized String getNextId(String name) throws SQLException { 
   SqlMapSession sequenceSession=SessionManager.retrieveSession(); 
   ISequence sequence = (ISequence) sequenceSession.queryForObject( 
        "getSequenceById", name); 
   if (sequence == null) { 
    throw new SQLException("Error: A null sequence was returned from the database" + 
      " (could not get next "+ name + " sequence)."); 
   } 
   String id = sequence.getNextId(); 
   sequence.setNextId((new BigDecimal(id).add(new BigDecimal(5))).toString()); 
   sequenceSession.startTransaction(); 
   sequenceSession.update("updateSequence", sequence); 
   sequenceSession.commitTransaction(); 
   sequenceSession.close(); 
   return String.valueOf(sequence.getNextId()); 
  } 


 

常见的类关系与实现

对于类与类之间的引用关系,最常见的是一对一,一对多与多对多。下面就讲述对这三种关系的实现。

一对一映射

在类与类之间关系中,一对一是最简单的一种。在每个类中有一个对其他类的引用,反之亦然。此时只需在 ibatis 的 result map 中建立对对象的引用关系即可:


清单 5. 一对一的引用

  1. <result property="belongedCatalog" column="A_BELONGEDCATALOG"   
  2. select="getArticleCatalogById"/>   
 <result property="belongedCatalog" column="A_BELONGEDCATALOG" 
 select="getArticleCatalogById"/> 

在上面的 mapping 中,A_BELONGEDCATALOG 为查询结果中的一个字段,而 getArticleCatalogById 为一个返回结果为 Catalog 的查询。因此 ibatis 在调用时,将会把 A_BELONGEDCATALOG 作为参数传入 getArticleCatalogById 来生成一个 Catalog 实例的引用 , 并将改引用赋值给 belongedCatalog 属性。

一对多映射

一对多关系与 1 对 1 关系的区别之处在于类中引用的对象为一个列表而非单个对象,因此在 resultmap 中的 mapping 是一样的,唯一的区别在于关联的 select 返回的为一个列表而非单个对象(上例中的 getArticleCatalogById 的返回结果为一个对象,而对于一对多关系此方法将返回一个列表)。因此在这里不再给出实现。

多对多

在实现多对多关系时,每个类都可能包含多个对对方类的引用列表,通常需要建立一张关系表用来存储关系映射,如下所示:


清单 6. 多对多的关系表

  1. CREATE TABLE `ARTICLE_GROUP_RELATION` (   
  2.  `GROUPID` varchar(10) not null ,   
  3.  `ARTICLEID` varchar(10) not null );  
CREATE TABLE `ARTICLE_GROUP_RELATION` ( 
 `GROUPID` varchar(10) not null , 
 `ARTICLEID` varchar(10) not null );


 

在这里 Article 与 Group 两个对象之间存在多对多关系,GROUPID 与 ARTICLEID 字段分别对应与 Group 表与 Article 表的主键。若在 Group 对象中有一个对 Article 列表的引用,首先需要在 Group 的 resultmap 中定义一个 List 的属性。这个属性会映射到一条根据 GroupID 查出 Article 的语句 getArticleByArticleGroupId,该查询需要将上面定义的关系表与 Article 表进行连接,返回结果为一个 Article 的列表 :


清单 7. 多对多的关系映射

  1.               
  2. <result property="articleList" column="AG_ID" select="getArticleByArticleGroupId"/>   
  3. <select id="getArticleByArticleGroupId" resultMap="getArticleResult"   
  4. parameterClass="string">   
  5. SELECT   
  6. `ARTICLE`.`ID` AS `A_ID`, `ARTICLE`.`NAME` AS `A_NAME`, `ARTICLE`.`INDUSTRY`   
  7. AS `A_ISINDUSTRY`, `ARTICLE`.`UPDATEDATE` AS `A_UPDATEDATE`   
  8. FROM ` ARTICLE `, ` ARTICLE_GROUP_RELATION `   
  9. WHERE `ARTICLE_GROUP_RELATION`.`GROUPID` = #id# AND   
  10. `ARTICLE_GROUP_RELATION`.`ARTICLEID` = `ARTICLE`.`ID`   
  11. </select>  
				
 <result property="articleList" column="AG_ID" select="getArticleByArticleGroupId"/> 
 <select id="getArticleByArticleGroupId" resultMap="getArticleResult" 
 parameterClass="string"> 
 SELECT 
 `ARTICLE`.`ID` AS `A_ID`, `ARTICLE`.`NAME` AS `A_NAME`, `ARTICLE`.`INDUSTRY` 
 AS `A_ISINDUSTRY`, `ARTICLE`.`UPDATEDATE` AS `A_UPDATEDATE` 
 FROM ` ARTICLE `, ` ARTICLE_GROUP_RELATION ` 
 WHERE `ARTICLE_GROUP_RELATION`.`GROUPID` = #id# AND 
 `ARTICLE_GROUP_RELATION`.`ARTICLEID` = `ARTICLE`.`ID` 
 </select>

需要注意的是,在对应的增加 / 删除 / 修改操作中,也需要调用一个 SQL 语句来更新关系表,否则会导致表中的数据不一致,以删除为例:


清单 8. 多对多的删除语句

  1. <delete id="deleteArticleGroupArticleList" parameterClass="string" >   
  2.  DELETE FROM `ARTICLE_GROUP_RELATION` WHERE `GROUPID` = #id#   
  3.  </delete>   
<delete id="deleteArticleGroupArticleList" parameterClass="string" > 
 DELETE FROM `ARTICLE_GROUP_RELATION` WHERE `GROUPID` = #id# 
 </delete> 


 

复合关系的分类与实现

上一章介绍了类之间的关系的实现,本章在上一章的基础上,介绍了几种对象主键与继承类关系的实现。

对象主键

对象主键是一种非常特殊的主键实现,此时不是使用一个自动增长的 ID 作为类的主键,而是将类中所引用到的某个对象作为主键。因此,在建表的时候就需要将主键对象表中的主键字段作为该表中的主键字段保存,同样在进行 resultmap 的定义时需要建立一个对与其他对象的引用:

在下面这个例子中,UserCredit 对象中包含一个 createUser 对象并以该对象作为主键,而 User 对象本身包含了两个主键:用户 ID 与注册系统。因此在对 UserCredit 建表时将 USERID 跟 REGISTEREDSYSTEM 作为两个字段存放,对应的在映射时需要将这两个字段一起映射到 user 对象的查询上。对应的字段映射与查询语句如下:

清单 9. 对象主键的关系映射

  1. <result property="createUser" column="userIdUSERID ,   
  2.  registeredSystem= REGISTEREDSYSTEM" select="getUserById"/>   
  3.   
  4.  <select id="getUserById" resultMap="getUserResult"   
  5.  parameterClass="java.util.HashMap" >    
  6.  SELECT   
  7.  `SYUSR`.`USERID` AS `U_USERID`, `SYUSR`.`SYSCODE` AS   
  8.  `U_REGISTEREDSYSTEM`, `SYUSR`.`NAME` AS `U_NAME`,   
  9.  `SYUSR`.`SYSNAME` AS `U_DISPNAME`, `SYUSR`.`GENDER` AS `U_GENDER`,   
  10.  `SYUSR`.`MOBILE` AS `U_MOBILE`, `SYUSR`.`EMAIL` AS `U_EMAIL   
  11.  FROM `SYUSR`   
  12.  WHERE   
  13.  `USERID` = #userId# AND `SYSCODE` = #registeredSystem#   
  14.  </select>   
  15.  <select id="getUserCreditByUser" resultMap="getUserCreditResult"   
  16.  parameterClass="java.util.HashMap">   
  17.  SELECT `NUMBER`, `NUMBERREMAIN`, ` USERID `, `SYSCODE`   
  18.  FROM `CREDIT`   
  19.  WHERE `CREDIT`.` USERID ` = #userId# AND `CREDIT`.`SYSCODE` = #registeredSystem#   
  20.  </select>   
<result property="createUser" column="userId= USERID , 
 registeredSystem= REGISTEREDSYSTEM" select="getUserById"/> 

 <select id="getUserById" resultMap="getUserResult" 
 parameterClass="java.util.HashMap" >  
 SELECT 
 `SYUSR`.`USERID` AS `U_USERID`, `SYUSR`.`SYSCODE` AS 
 `U_REGISTEREDSYSTEM`, `SYUSR`.`NAME` AS `U_NAME`, 
 `SYUSR`.`SYSNAME` AS `U_DISPNAME`, `SYUSR`.`GENDER` AS `U_GENDER`, 
 `SYUSR`.`MOBILE` AS `U_MOBILE`, `SYUSR`.`EMAIL` AS `U_EMAIL 
 FROM `SYUSR` 
 WHERE 
 `USERID` = #userId# AND `SYSCODE` = #registeredSystem# 
 </select> 
 <select id="getUserCreditByUser" resultMap="getUserCreditResult" 
 parameterClass="java.util.HashMap"> 
 SELECT `NUMBER`, `NUMBERREMAIN`, ` USERID `, `SYSCODE` 
 FROM `CREDIT` 
 WHERE `CREDIT`.` USERID ` = #userId# AND `CREDIT`.`SYSCODE` = #registeredSystem# 
 </select> 


 

需要注意的是,在 getUserById 中接受的参数为一个 HahsMap,这个 HashMap 中存放了两个字段:userId 和 registeredSystem。因此在映射是需要写成 column="userId= USERID , registeredSystem= REGISTEREDSYSTEM"的方式来传入一个 Map 参数。

对于对象主键的查询语句,可以将参数设为一个对象,也可以将参数设为一个 Map,在 Map 中放入 userId 与 registeredSystem,在查询时使用这两个值作为查询条件。类似的在其他增加 / 删除 / 修改操作时也可以传入一个 HashMap 作为参数。

一对多与多对多时的对象主键

在上一小节的基础上,如果某个以对象为主键的类被其他类所引用并建立了一对多或者多对多的关系,此时在 mapping 时需要把前一章中使用的关联的 id 改成对象的主键。下面是一对多的示例,首先在 resultmap 中定义属性映射,然后定义了对应的查询方法。


清单 10. 一对多对象主键的关系映射

  1. <result property="groupList" column="userIdUSERID ,   
  2.  registeredSystem= REGISTEREDSYSTEM" select=" getAttrListByUser "/>   
  3.  <select id="getAttrListByUser" resultMap="getAttrResult"   
  4.  parameterClass="java.util.HashMap">   
  5.  SELECT `ATTRIBUTENAME`, `ATTRIBUTEVALUE`, ` USERID `, `SYSCODE`   
  6.  FROM `ATTRIBUTE`   
  7.  WHERE `ATTRIBUTE`.`USERID` = #userId# AND   
  8.  `ATTRIBUTE`.`SYSCODE` = #registeredSystem#   
  9.  </select>   
<result property="groupList" column="userId= USERID , 
 registeredSystem= REGISTEREDSYSTEM" select=" getAttrListByUser "/> 
 <select id="getAttrListByUser" resultMap="getAttrResult" 
 parameterClass="java.util.HashMap"> 
 SELECT `ATTRIBUTENAME`, `ATTRIBUTEVALUE`, ` USERID `, `SYSCODE` 
 FROM `ATTRIBUTE` 
 WHERE `ATTRIBUTE`.`USERID` = #userId# AND 
 `ATTRIBUTE`.`SYSCODE` = #registeredSystem# 
 </select> 


 

将上面的对象主键与前面提到的多对多关系结合起来,可以得到最复杂的多对多的对象主键的实现。首先在关系表中需要加入对于对象主键的定义。假设 Article 对象为多主键对象,在 Article 中有一个 GroupList 的属性,Article 与 Group 有多对多的关系,以下为表的定义与 resultmap 的实现:


清单 11. 一对多对象主键的关系映射

  1. CREATE TABLE `ARTICLE_GROUP_RELATION` (   
  2.  `GROUPID` varchar(10) not null ,   
  3.  `ARTICLETITLE` varchar(10) not null,   
  4.  `ARTICLEUSER` varchar(10) not null );   
  5.  <result property="groupList" column=" articleTitle=TITLE,   
  6.  articleUser=USERID" select="getGroupByArticle"/>   
  7.   
  8.  <select id="getGroupByArticle" resultMap="getGroupResult"   
  9.  parameterClass="java.util.HashMap">   
  10.  SELECT   
  11.  `GROUP`.`NAME` AS `G_NAME`, `GROUP`.`ID` AS `G_ID`   
  12.  FROM ` GROUP `, ` ARTICLE_GROUP_RELATION `   
  13.  WHERE `ARTICLE_GROUP_RELATION`.`GROUPID` = GROUP.`ID` AND   
  14.  `ARTICLE_GROUP_RELATION`.`ARTICLETITLE` = #articleTitle# AND   
  15.  `ARTICLE_GROUP_RELATION`.`ARTICLEUSER` = #articleUser#   
  16.  </select>   
  17.  <delete id="deleteArticleGroupArticleList" parameterClass="java.util.HashMap" >   
  18.  DELETE FROM `ARTICLE_GROUP_RELATION`   
  19.  WHERE `GROUPID` = #groupId# AND   
  20.  `ARTICLE_GROUP_RELATION`.`ARTICLETITLE` = #articleTitle# AND   
  21.  `ARTICLE_GROUP_RELATION`.`ARTICLEUSER` = #articleUser#   
  22.  </delete>   
CREATE TABLE `ARTICLE_GROUP_RELATION` ( 
 `GROUPID` varchar(10) not null , 
 `ARTICLETITLE` varchar(10) not null, 
 `ARTICLEUSER` varchar(10) not null ); 
 <result property="groupList" column=" articleTitle=TITLE, 
 articleUser=USERID" select="getGroupByArticle"/> 

 <select id="getGroupByArticle" resultMap="getGroupResult" 
 parameterClass="java.util.HashMap"> 
 SELECT 
 `GROUP`.`NAME` AS `G_NAME`, `GROUP`.`ID` AS `G_ID` 
 FROM ` GROUP `, ` ARTICLE_GROUP_RELATION ` 
 WHERE `ARTICLE_GROUP_RELATION`.`GROUPID` = GROUP.`ID` AND 
 `ARTICLE_GROUP_RELATION`.`ARTICLETITLE` = #articleTitle# AND 
 `ARTICLE_GROUP_RELATION`.`ARTICLEUSER` = #articleUser# 
 </select> 
 <delete id="deleteArticleGroupArticleList" parameterClass="java.util.HashMap" > 
 DELETE FROM `ARTICLE_GROUP_RELATION` 
 WHERE `GROUPID` = #groupId# AND 
 `ARTICLE_GROUP_RELATION`.`ARTICLETITLE` = #articleTitle# AND 
 `ARTICLE_GROUP_RELATION`.`ARTICLEUSER` = #articleUser# 
 </delete> 


 

上面的 getGroupByArticle 为一条根据 Article 查出 Group 的语句,该查询需要将关系表与 Groupe 表 join,返回结果为一个 Group 的列表。同样需要注意的是,在对应的增加 / 删除 / 修改操作中,也需要调用一个 SQL 语句来更新关系表,上面是删除的例子。

类的继承的特殊处理

类的继承关系是一种非常常见的类关系,在一般的应用中都会涉及。一般会将一些公有的属性与方法放在一个父类中,然后不同的子类继承父类。在进行数据库的映射时,对于继承关系可以有两种处理方法。第一种是对于父类并不单独建表与之对应,而是分别对每个子类分别建表与做映射,所有父类的属性都在子类中保存有一份。这种方法的好处是在进行映射时非常简单,与一般类的处理相同,坏处是是并利用类的继承的特点,子类的表中会有大量重复的属性。第二种方法是对于父类建立一张表与之对应,对于每一个子类也单独建立一张表与之对应,但是在子类当中并不保存父类的属性,父类的属性只保存在父类的表当中。对于所有的父类与子类,都采用一套相同的 id,这就是说如果子类的表中有一行 ID 值为 10 的数据,在父类表中也会有一行 ID 值为 10 的数据。这两行数据分别存放子类与父类中的属性值。为了区分具体的值是属于哪个子类,在父类中需要定义一个特殊字段 CLASSKEY,这个字段的值表示该行是属于哪个字段。这种方法也是在很多 O/R mapping 工具中常用的方法,下面将详细讲述这种方法的实现。在下面的这里实现示例中有三个类:Customer(客户),ComanyCustomer(公司客户), PersonCustomer(个人客户)。 Customer 为一个父类,ComanyCustomer 与 PersonCustomer 继承了 Customer。在数据库中对应的有三张表 CUSTOMER, COMPANYCUSTOMER 和 PERSONCUSTOMER。 在下面的实现中,“COM”为 ComanyCustome 类所对应的 Class Keyr,“PERSON”为 PersonCustomer 对应的 Class Key。在进行查询的时候需要将子表与父表相 join,在进行增加 / 删除 / 修改操作的时候,也需要同时更改父类表与子类表,如增加中需要同时调用下面的两条增加语句。


清单 12. 继承关系的实现

  1. <select id="getCompanyCustomerByID" resultMap="getCompanyCustomerResult"   
  2.  parameterClass="string">   
  3.  SELECT   
  4.  `CUSTOMER`.`NAME` AS `C_NAME`, `COMPANYCUSTOMER`.`ID`   
  5.  AS `C_ID`, `COMPANYCUSTOMER`.`LICENSE` AS `C_ LICENSE`   
  6.  FROM `COMPANYCUSTOMER`, `CUSTOMER`   
  7.  WHERE `COMPANYCUSTOMER`.`ID` = `CUSTOMER`.`ID` AND   
  8.  `CUSTOMER`.`CLASSKEY` = ‘ COM ’ AND   
  9.  `COMPANYCUSTOMER`.`ID` = #id#   
  10.  </select>   
  11. <PRE class=html name="code">public Customer getCustomerById(String id)   
  12.  {   
  13.  String classKey=(String) sqlSession.queryForObject("getClassKeyByID", id);   
  14.  if(“COM”.equals(classKey))   
  15.      return (Customer) sqlSession.queryForObject("getCompanyCustomerByID", id);   
  16.    else   
  17.    if(“PERSON”.equals(classKey))   
  18.      return (Customer) sqlSession.queryForObject("getPersonCustomerByID", id);   
  19.  }   
  20. </PRE><BR>  
  21. <insert id="insertCustomer" parameterClass="Customer"> INSERT INTO `CUSTOMER` (`CUSTOMER`.`ID`, `CUSTOMER`.`CLASSKEY`, `CUSTOMER`.` NAME `) VALUES ( #id#, #classKey#,#name#) </insert> <insert id="insertComanyCustomer" parameterClass="ComanyCustomer"> INSERT  
  22.  INTO `COMPANYCUSTOMER` (`COMPANYCUSTOMER`.`ID`, `COMPANYCUSTOMER`.` NAME `) VALUES ( #id#, #license#) </insert> <select id="getClassKeyByID" resultClass="string” parameterClass="string"> SELECT `CUSTOMER`.` CLASSKEY` AS `C_ CLASSKEY` FROM `CUSTOMER` WHERE  
  23.  `CUSTOMER`.`ID` = #id# </select>  
  24. <PRE></PRE>  
  25. <P><BR>  
  26.  </P>  
  27. <P>继承关系比其他关系复杂的实现是在 java 类也需要做一些特殊的处理,在引用 Customer 类的时候,可以直接引用父类或子类。引用父类时可能指向的是一个 ComanyCustomer 的实例,也可能是一个 PersonalCustomer 的实例。然而在仅仅知道 id 的时候无法判断是哪一个具体的子类,在这个时候,就需要根据 ClassKey 来判读具体是哪一个实例了。首先需要有一个方法获取 ClassKey,然后根据 ClassKey 来调用获取具体子类的语句。  
  28. </P>  
  29. <P sizcache="0" sizset="56"><A name=listing13><STRONG>清单 13. 继承关系的 Java 实现</STRONG></A></P>  
  30. <PRE class=html name="code">public Customer getCustomerById(String id)   
  31.  {   
  32.  String classKey=(String) sqlSession.queryForObject("getClassKeyByID", id);   
  33.  if(“COM”.equals(classKey))   
  34.      return (Customer) sqlSession.queryForObject("getCompanyCustomerByID", id);   
  35.    else   
  36.    if(“PERSON”.equals(classKey))   
  37.      return (Customer) sqlSession.queryForObject("getPersonCustomerByID", id);   
  38.  }   
  39. </PRE>  
  40. <P><BR>  
  41.  </P>  
  42. <P sizcache="0" sizset="57"><A name=major5><SPAN class=atitle>总结</SPAN></A></P>  
  43. <P>本文介绍了关于 iBatis 开发中常用的映射的实现,由于 iBatis 的所有语句必须靠开发人员生成,上面描述的种种对象关系和给出的实现实例将对开发 iBatis 的应用具有非常大的指导意义。  
  44. </P>  
  45. <P> </P>  
<select id="getCompanyCustomerByID" resultMap="getCompanyCustomerResult" 
 parameterClass="string"> 
 SELECT 
 `CUSTOMER`.`NAME` AS `C_NAME`, `COMPANYCUSTOMER`.`ID` 
 AS `C_ID`, `COMPANYCUSTOMER`.`LICENSE` AS `C_ LICENSE` 
 FROM `COMPANYCUSTOMER`, `CUSTOMER` 
 WHERE `COMPANYCUSTOMER`.`ID` = `CUSTOMER`.`ID` AND 
 `CUSTOMER`.`CLASSKEY` = ‘ COM ’ AND 
 `COMPANYCUSTOMER`.`ID` = #id# 
 </select>
  1. public Customer getCustomerById(String id)   
  2.  {   
  3.  String classKey=(String) sqlSession.queryForObject("getClassKeyByID", id);   
  4.  if(“COM”.equals(classKey))   
  5.      return (Customer) sqlSession.queryForObject("getCompanyCustomerByID", id);   
  6.    else   
  7.    if(“PERSON”.equals(classKey))   
  8.      return (Customer) sqlSession.queryForObject("getPersonCustomerByID", id);   
  9.  }   
public Customer getCustomerById(String id) 
 { 
 String classKey=(String) sqlSession.queryForObject("getClassKeyByID", id); 
 if(“COM”.equals(classKey)) 
     return (Customer) sqlSession.queryForObject("getCompanyCustomerByID", id); 
   else 
   if(“PERSON”.equals(classKey)) 
     return (Customer) sqlSession.queryForObject("getPersonCustomerByID", id); 
 } 
 <insert id="insertCustomer" parameterClass="Customer"> INSERT INTO `CUSTOMER` (`CUSTOMER`.`ID`, `CUSTOMER`.`CLASSKEY`, `CUSTOMER`.` NAME `) VALUES ( #id#, #classKey#,#name#) </insert> <insert id="insertComanyCustomer" parameterClass="ComanyCustomer"> INSERT INTO `COMPANYCUSTOMER` (`COMPANYCUSTOMER`.`ID`, `COMPANYCUSTOMER`.` NAME `) VALUES ( #id#, #license#) </insert> <select id="getClassKeyByID" resultClass="string” parameterClass="string"> SELECT `CUSTOMER`.` CLASSKEY` AS `C_ CLASSKEY` FROM `CUSTOMER` WHERE `CUSTOMER`.`ID` = #id# </select>


 

继承关系比其他关系复杂的实现是在 java 类也需要做一些特殊的处理,在引用 Customer 类的时候,可以直接引用父类或子类。引用父类时可能指向的是一个 ComanyCustomer 的实例,也可能是一个 PersonalCustomer 的实例。然而在仅仅知道 id 的时候无法判断是哪一个具体的子类,在这个时候,就需要根据 ClassKey 来判读具体是哪一个实例了。首先需要有一个方法获取 ClassKey,然后根据 ClassKey 来调用获取具体子类的语句。

清单 13. 继承关系的 Java 实现

  1. public Customer getCustomerById(String id)   
  2.  {   
  3.  String classKey=(String) sqlSession.queryForObject("getClassKeyByID", id);   
  4.  if(“COM”.equals(classKey))   
  5.      return (Customer) sqlSession.queryForObject("getCompanyCustomerByID", id);   
  6.    else   
  7.    if(“PERSON”.equals(classKey))   
  8.      return (Customer) sqlSession.queryForObject("getPersonCustomerByID", id);   
  9.  }   
public Customer getCustomerById(String id) 
 { 
 String classKey=(String) sqlSession.queryForObject("getClassKeyByID", id); 
 if(“COM”.equals(classKey)) 
     return (Customer) sqlSession.queryForObject("getCompanyCustomerByID", id); 
   else 
   if(“PERSON”.equals(classKey)) 
     return (Customer) sqlSession.queryForObject("getPersonCustomerByID", id); 
 } 


 

总结

本文介绍了关于 iBatis 开发中常用的映射的实现,由于 iBatis 的所有语句必须靠开发人员生成,上面描述的种种对象关系和给出的实现实例将对开发 iBatis 的应用具有非常大的指导意义。

 

<!--192.168.1.236-->
分享到:
评论

相关推荐

    iBatis开发指南和一个iBatis实例

    例如,你可能看到如何使用iBatis进行增删改查操作,以及如何处理复杂查询,如联接查询、子查询等。 "iBatis开发指南"则是更全面的官方文档,它包含了iBatis的所有特性和使用方法。从中,你可以学习到动态SQL的使用...

    Ibatis 入门经典 实例

    Ibatis 作为一款 ORM(对象关系映射)框架,允许开发者编写动态 SQL,通过 XML 或注解的方式将 SQL 语句与 Java 代码分离,提高了代码的可读性和维护性。相较于传统的 JDBC,Ibatis 提供了更灵活的数据访问层,使得...

    IBATIS开发使用实例

    本文将围绕“IBATIS开发使用实例”这一主题,深入解析复杂SQL查询的应用,尤其是如何利用SQL进行多表关联、条件筛选以及聚合函数的使用。 ### IBATIS简介 IBATIS,现被称为MyBatis,是一种优秀的持久层框架,它...

    Ibatis.net学习和实例~

    Ibatis.net的核心理念是SQL映射,它允许开发者编写原生的SQL查询,而不是依赖于ORM(对象关系映射)的复杂性。通过XML配置文件或者注解,你可以将SQL语句与.NET对象绑定,使得数据库操作更加直观和高效。学习Ibatis...

    ibatis学习完整实例,例子

    通过深入学习和实践"ibatistest2"这个实例,开发者不仅可以掌握Ibatis的基本使用,还能理解其在实际项目中的应用方式,为日后的开发工作打下坚实的基础。记住,理论与实践相结合,才能真正掌握一门技术,希望...

    iBatis Web用法实例

    在XML文件中,可以使用`&lt;parameterMap&gt;`和`&lt;resultMap&gt;`标签来定义复杂的参数映射和结果映射,包括Java对象与数据库字段之间的映射关系。 8. **动态SQL**: iBatis支持动态SQL,可以通过`&lt;if&gt;`, `&lt;choose&gt;`, `...

    IBatis .NET框架实例

    通过使用XML或注解来配置和映射SQL,IBatis使得数据访问更加灵活且易于维护。 **二、安装与集成** 在.NET项目中引入IBatis通常通过NuGet包管理器完成。安装完成后,需要在项目中配置IBatis的主配置文件(如:ibatis...

    ibatis +mysql 实例

    这个"ibatis + mysql 实例"提供了一个具体的案例,演示了如何结合这两个技术进行基本的数据操作,如增、删、改、查。Ibatis是一个轻量级的Java持久层框架,它允许开发者将SQL语句直接写在配置文件中,与传统的JDBC...

    Ibatis应用实例.docx

    《Ibatis应用实例》 iBatis是一个轻量级的持久层框架,它作为O/R Mapping解决方案,与Hibernate等其他框架相比,其最大的优势在于简洁易用。对于不需要复杂功能的项目,iBatis是理想的选择,它允许开发者自由地编写...

    IBatis开发实例

    IBatis(现更名为MyBatis)是由Clinton Begin创建的一款Java ORM(对象关系映射)框架,它允许开发者编写SQL语句而不必过于关注数据访问层的复杂性。通过XML或注解方式配置,IBatis将SQL与Java代码分离,提供更灵活...

    iBatis入门实例详细代码

    iBatis是一个轻量级的Java持久层框架,它提供了SQL映射框架,将SQL语句与Java代码分离,使得开发者能够更...随着对iBatis的深入理解和实践,你会发现它在处理复杂SQL和对象关系映射方面具有很高的灵活性和可扩展性。

    ibatis文档

    这个文档集主要涵盖了iBATIS的安装、配置以及如何使用映射语句处理数据操作,特别是复杂对象数据关系的处理。让我们深入探讨这些关键知识点。 首先,**iBATIS的安装和配置**是使用iBATIS的第一步。在Java环境中,...

    ibatis+oracle实例

    2. **事务管理**:Ibatis提供了对数据库事务的控制,可以配合Oracle的ACID特性处理复杂的事务场景。 3. **存储过程调用**:Ibatis可以通过`&lt;select&gt;`、`&lt;procedure&gt;`元素调用Oracle的存储过程,增强业务逻辑的封装...

    ibatis的使用教程

    Ibatis 使用不同的标签来处理不同的数据库操作: - `&lt;select&gt;` 标签用于查询,其中包含 SQL 语句,并设置 `resultClass` 属性指定返回结果的类型。 - `&lt;insert&gt;` 标签用于插入数据,设置 `parameterClass` 指定输入...

    ibatis3应用实例(oracle数据库)

    Ibatis3的主要优势在于灵活性高,可以方便地处理复杂的SQL操作,同时降低了学习和使用的门槛。 二、Oracle数据库概述 Oracle数据库是一款高性能、高可靠性的关系型数据库管理系统,广泛应用于企业级应用。其强大的...

    ibatis完整实例

    Ibatis 是一个优秀的轻量级 Java ORM(对象关系映射)框架,它提供了一种灵活的方式来将 SQL 查询映射到 Java 对象,避免了传统 JDBC 编程中的大量手动代码。在这个"ibatis 完整实例"中,我们将会探讨如何使用 ...

    asp.net MVC3 IBATIS.NET 实例

    然后,实现该接口,使用IBATIS.NET的SqlMap对象执行SQL查询。 5. **控制器(Controller)**: 在MVC架构中,控制器接收HTTP请求,调用业务逻辑,并返回响应。你需要创建一个控制器类,其中包含一个动作方法,该方法...

    iBATIS实例小程序

    ### iBATIS实例小程序知识点解析 #### 一、iBATIS简介 iBATIS是一个开源的持久层框架,它提供了一种将对象映射到关系型数据库中的...通过掌握这些知识点,开发者可以更加高效地利用iBATIS完成复杂的数据处理任务。

    ibatis入门实例(全代码)

    Ibatis 是一个优秀的轻量级 Java ORM(对象关系映射)框架,它允许开发者将 SQL 查询与 Java 代码分离,使得数据访问层更加灵活和易于维护。在这个"ibatis入门实例(全代码)"中,我们将探讨如何通过 Ibatis 实现对...

    基于struts2 spring ibatis poi开发的导出Excel实例

    **填充数据**:使用POI将查询结果填充到Excel的单元格中,可以是行、列或者复杂的数据结构。 e. **响应下载**:在Struts2的动作类中,设置HTTP响应头,指定Content-Type为"application/vnd.ms-excel",并设置...

Global site tag (gtag.js) - Google Analytics