MyException - 我的异常网
当前位置:我的异常网» SQL » Mybatis透过一条SQL查出关联的对象

Mybatis透过一条SQL查出关联的对象

www.MyException.Cn  网友分享于:2013-09-28  浏览:0次
Mybatis通过一条SQL查出关联的对象

以往在做对象的查询时如果需要把关联的对象一起查出来是通过resultMap的子查询来进行的,这种用法可以参考我之前写的一篇文章http://elim.iteye.com/blog/1337009。通过子查询来进行的关联对象的查询时,Mybatis会重新发起一次数据库请求,这在有的时候性能方面不是特别的好,我们期望可以用一条SQL语句就把主体对象以及关联的对象都查出来,hibernate其实是有对应的实现,Mybatis现在也有对应的支持(笔者以前刚开始接触Mybatis时Mybatis还没有这个机制,不知道是从哪个版本开始有了这个功能,挺好的)。

 

       现在假设我们有两张表,sys_wf_process表和sys_wf_node表。sys_wf_process表是流程实例表,sys_wf_node是流程节点表,流程节点表通过process_id字段关联sys_wf_process表的主键id,一个流程实例会有很多流程节点,二者的表结构如下所示。

 

sys_wf_process表

字段名

类型

备注

id

integer

主键

template_id

integer

模板ID

creator

integer

创建人的ID

create_time

timestamp

创建时间

 

sys_wf_node表

字段名

类型

备注

id

integer

主键

process_id

integer

流程实例ID

node_code

varchar(10)

节点编号

node_name

varchar(100)

节点名称

 

       针对这两张表,我们分别建立了对应的实体类与之对应,sys_wf_process表对应的实体对象是SysWfProcess,sys_wf_node表对应的实体类是SysWfNode。二者的代码如下(对应的set和get方法将被省略)。

public class SysWfProcess {

  

    private Integer id;

 

    private Integer templateId;//模板ID

 

    private Integer creator;

 

    private Date createTime;

   

    private List<SysWfNode> nodes;//包含的流程节点   

   //…省略get和set方法

}

 

public class SysWfNode {

  

    private Integer nodeId;//主键

 

    private Integer processId;//流程实例ID

   

    private SysWfProcess process;//关联的流程实例  

 

    private String nodeCode;//节点编号

 

    private String nodeName;//节点名称

 

    //…省略getset方法

}

 

         SysWfProcess和SysWfNode是一对多的关系,下面将分三种情况来讨论对应的配置,通过1拿多,通过多拿1,以及相互拿(即双向的引用)。

 

1.1     通过1拿多

       在本例中1的一方是SysWfProcess,其通过属性nodes引用多的一方。如果通过一条SQL在查询1的一方自动把多的一方也查询出来,我们通常是通过表的关联查询来查询出所有相关的信息。为此我们在对应的Mapper.xml文件中加入如下查询配置。

   <!-- 只用一条SQL查出一对多关系 -->

   <select id="singleSql1ToN" parameterType="Java.lang.Integer"resultMap="SingleSql1ToNResult">

      select

       a.id,a.template_id,a.creator,a.create_time,b.id node_id,b.node_code, b.node_name

      from sys_wf_process a

        left join sys_wf_node b

           on a.id=b.process_id

      where a.id=#{id}

   </select>

 

       以及对应的resultMap配置。

   <resultMap id="SingleSql1ToNResult"type="com.elim.learn.mybatis.model.SysWfProcess">

      <!-- id非常重要,用来区分记录 -->

      <id property="id" column="id"/>

      <result property="creator" column="creator"/>

      <result property="templateId" column="template_id"/>

      <result property="createTime" column="create_time"/>

      <!-- 指定关联的集合属性的数据映射,ofType属性指定集合元素对应的数据类型 -->

      <collection property="nodes"ofType="com.elim.learn.mybatis.model.SysWfNode">

        <id property="nodeId" column="node_id"/>

        <result property="nodeCode" column="node_code"/>

        <result property="nodeName" column="node_name"/>

        <result property="processId" column="id"/>

      </collection>

   </resultMap>

 

       关联的集合属性是通过collection元素来定义的,跟通过resultMap指定子查询使用的元素是一样的,只是这里不指定子查询,而是直接配置从同一个查询结果集里面进行映射。按照上面这种配置Mybatis会把结果集里面的每一行的node_id、node_code、node_name和id字段取出根据映射关系构造为一个SysWfNode对象。

 

       然后我们也在对应的Mapper接口里面加入刚刚定义的查询方法。

public interface SysWfProcessMapper {

    SysWfProcess singleSql1ToN(Integer id);

}

 

       测试一下,看是否能正常拿到SysWfProcess关联的SysWfNode,代码如下:

public class BasicTest {

 

   private SqlSessionFactory sessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();

   private SqlSession session = null;

  

   @Before

   public void before() {

      session = sessionFactory.openSession();

   }

  

   @After

   public void after() {

      session.commit();

      session.close();

   } 

   @Test

   public void test3() {

      SysWfProcessMapper mapper = session.getMapper(SysWfProcessMapper.class);

      SysWfProcess process = mapper.singleSql1ToN(1);

      List<SysWfNode> nodes = process.getNodes();

      System.out.println(nodes);//这里可以输出获取到的SysWfNode信息

   }

  

}

 

1.2     通过多拿1

       通过一条SQL语句在查询一的一方时把多的一方也查出来,我们需要在查询时把所有关联的信息都查询出来,在对应的Mapper.xml文件中添加如下配置。

   <!-- 只用一条SQL查出多对一关系 -->

   <select id="singleSqlNTo1" parameterType="java.lang.Integer"resultMap="SingleSqlNTo1Result">

      select

        a.id,a.node_code,a.node_name,a.process_id, b.template_id,b.creator,b.create_time

      from

        sys_wf_node a, sys_wf_process b

      where

        a.process_id=b.id and a.id=#{id}

   </select>

  

   <resultMap type="com.elim.learn.mybatis.model.SysWfNode"id="SingleSqlNTo1Result">

      <id property="nodeId" column="id"/>

      <result property="nodeCode" column="node_code"/>

      <result property="nodeName" column="node_name"/>

      <result property="processId" column="process_id"/>

      <!-- 单个对象的关联是通过association元素来定义的 -->

      <association property="process"javaType="com.elim.learn.mybatis.model.SysWfProcess">

        <id property="id" column="process_id"/>

        <result property="templateId" column="template_id"/>

        <result property="creator" column="creator"/>

        <result property="createTime" column="create_time"/>

      </association>

   </resultMap>

 

       然后我们在对应的Mapper接口中定义与查询id相同名称的方法。

public interface SysWfNodeMapper {

    SysWfNode singleSqlNTo1(Integer id);

}

 

       测试如下:

   @Test

   public void test4() {

      SysWfNodeMapper mapper = session.getMapper(SysWfNodeMapper.class);

      SysWfNode node = mapper.singleSqlNTo1(2);

      SysWfProcess process = node.getProcess();

      System.out.println(process);//这里能拿到对应的SysWfProcess

   }

 

1.3     双向引用

       当需要两边都持有对应的引用,引用里面又持有对应的引用时,基于单条查询SQL的方式好像配置不出来。笔者将SingleSql1ToNResult中的SysWfProcess引用的SysWfNode再引用对应的SysWfProcess,指定其解析的resultMap为SingleSql1ToNResult时将抛出java.lang.StackOverflowError,因为它们在进行循环引用,循环的新建对象、赋值。配置如下:

   <resultMap id="SingleSql1ToNResult"type="com.elim.learn.mybatis.model.SysWfProcess">

      <!-- id非常重要,用来区分记录 -->

      <id property="id" column="id"/>

      <result property="creator" column="creator"/>

      <result property="templateId" column="template_id"/>

      <result property="createTime" column="create_time"/>

      <!-- 指定关联的集合属性的数据映射,ofType属性指定集合元素对应的数据类型 -->

      <collection property="nodes"ofType="com.elim.learn.mybatis.model.SysWfNode">

        <id property="nodeId" column="node_id"/>

        <result property="nodeCode" column="node_code"/>

        <result property="nodeName" column="node_name"/>

        <result property="processId" column="id"/>

        <association property="process"javaType="com.elim.learn.mybatis.model.SysWfProcess"resultMap="SingleSql1ToNResult"/>

      </collection>

   </resultMap>

 

       所以这种循环相互拥有对方引用的通过配置是不OK的,但是如果我们仅仅是对其某些属性感兴趣,我们可以在里面的assocation时再通过result指定一层映射关系,这个时候我们就可以拿到SysWfNode对应的SysWfProcess对象了,但是它跟我们的拥有SysWfNode的SysWfProcess对象已经不是同一个对象了。基于这种情况的配置如下:

   <resultMap id="SingleSql1ToNResult"type="com.elim.learn.mybatis.model.SysWfProcess">

      <!-- id非常重要,用来区分记录 -->

      <id property="id" column="id"/>

      <result property="creator" column="creator"/>

      <result property="templateId" column="template_id"/>

      <result property="createTime" column="create_time"/>

      <!-- 指定关联的集合属性的数据映射,ofType属性指定集合元素对应的数据类型 -->

      <collection property="nodes"ofType="com.elim.learn.mybatis.model.SysWfNode">

        <id property="nodeId" column="node_id"/>

        <result property="nodeCode" column="node_code"/>

        <result property="nodeName" column="node_name"/>

        <result property="processId" column="id"/>

        <association property="process"javaType="com.elim.learn.mybatis.model.SysWfProcess"resultMap="SysWfProcess"/>

      </collection>

   </resultMap>

  

   <resultMap id="SysWfProcess"type="com.elim.learn.mybatis.model.SysWfProcess">

      <id property="id" column="id"/>

      <result property="creator" column="creator"/>

      <result property="templateId" column="template_id"/>

      <result property="createTime" column="create_time"/>

   </resultMap>

 

       对应的测试代码如下:

   @Test

   public void test5() {

      SysWfProcessMapper mapper = session.getMapper(SysWfProcessMapper.class);

      SysWfProcess process = mapper.singleSql1ToN(1);

      List<SysWfNode> nodes = process.getNodes();

      SysWfNode node = nodes.get(0);

      System.out.println(node.getProcess());//不为null

      System.out.println(process == node.getProcess());//false

   }

 

 

 

<resultMap id="BaseResultMap" type="UserCollection">
  <!-- 子信息 -->
  <association property="graveyard" column="{graveyard_id = object_id}"  javaType="Graveyard" select="selectGraveyard"></association>
 </resultMap>

 <select id="queryCollectionList" parameterType="string"
  resultMap="BaseResultMap">
  SELECT a.* from user_collection a  where user_id = #{userId} and
  object_type = 1
 </select>
 
 <select id="selectGraveyard" parameterType="java.util.HashMap" resultType="Graveyard">
  SELECT b.* from  graveyard b where graveyard_id = #{graveyard_id}
 </select>


 <delete id="deleteCollection" parameterType="java.util.List">
  delete from user_collection where user_collection_id in
  <foreach collection="list" item="id" open="(" separator=","
   close=")">
   #{id}
  </foreach>
 </delete>

 

 

 

 

 

 

文章评论

Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
如何成为一名黑客
如何成为一名黑客
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
程序员应该关注的一些事儿
程序员应该关注的一些事儿
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
一个程序员的时间管理
一个程序员的时间管理
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
 程序员的样子
程序员的样子
老程序员的下场
老程序员的下场
总结2014中国互联网十大段子
总结2014中国互联网十大段子
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
Java程序员必看电影
Java程序员必看电影
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
那些争议最大的编程观点
那些争议最大的编程观点
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
我是如何打败拖延症的
我是如何打败拖延症的
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
程序员的鄙视链
程序员的鄙视链
程序员必看的十大电影
程序员必看的十大电影
程序员都该阅读的书
程序员都该阅读的书
中美印日四国程序员比较
中美印日四国程序员比较
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
为什么程序员都是夜猫子
为什么程序员都是夜猫子
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
漫画:程序员的工作
漫画:程序员的工作
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
程序员和编码员之间的区别
程序员和编码员之间的区别
旅行,写作,编程
旅行,写作,编程
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
编程语言是女人
编程语言是女人
代码女神横空出世
代码女神横空出世
我的丈夫是个程序员
我的丈夫是个程序员
每天工作4小时的程序员
每天工作4小时的程序员
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有