MyBatis的关联映射(学习笔记)

  本文针对MyBatis的关联映射,重点在于:
(1)不同的关联关系(一对一、一对多、多对多)如何创建数据表和在对应的类中创建外键关联。
(2)如何在各个类的xml映射文件中进行配置。
在xml映射文件中确定了什么方法,这些方法如何实现。

1、一对一关联映射

1.1数据表:

tb_cardtb_person

1.2数据表关联:

在tb_person表中新增一栏card_id,和tb_card中的id进行关联:

FOREIGN KEY(card_id) REFERENCES tb_card(id);
1.3类关联:

  首先分别对照tb_card和tb_person创建两个类:CardPerson然后在Person类中新增一个属性Card,用于指向某个具体的card对象。

private Card card; 

  这里就开始会有一些困惑了。首先我们的Person类的其他属性都是和数据库中的tb_person一一对应的,照理来说,这里应该对应的是card_id但实际上这里是直接指向Card对象。

1.4 xml映射文件:
1.4.1xml映射文件——CardMapper.xml:

  定义了一个selectCardById方法。根据id查询返回Card对象,实现方式如下:

SELECT * from tb_card where id = #{id}
1.4.2 xml映射文件——PersonMapper.xml:

  定义了一个selectPersonById方法。根据id查询Person。按照常理应该是返回一个Person对象,但是这里希望查询出来的结果既包含Person又能包含Card。所以需要使用到resultMap来实现。
  首先还是通过Id找到Person对象,这个Person对象是resultMap的一部分。然后根据Person对象的card_id来调用CardMapper.xml中的selectCardById方法。这样又能得到Card对象,这个对象也是resultMap的一部分。

  也就是说,我们实现了通过Card的id查询card对象,通过Person的id查询Person对象(以及Card对象)。而为什么是实现了这些查询,例如为什么不能通过Card的id来查询Person对象。而为什么后面一对多中又有类似的操作呢。类中的定义的属性跟我们后面要实现的方法有没有什么联系呢。

2、一对多关联映射

  来看一下MyBatis中一对多的关联映射:

2.1 数据表:

tb_clazztb_student

2.2 数据表关联:

  在数据库中构建数据表的时候,外键在多方
  在tb_student表中新增一栏clazz_id,和tb_clazz中的id进行关联:

FOREIGN KEY(clazz_id) REFERENCES tb_clazz(id);
2.3 类关联:

  首先分别对照tb_clazz和tb_student创建两个类:ClazzStudent。这里是一对多关系,在Student类中新增一个属性Clazz,用于指向某个具体的Clazz对象。

private Clazz clazz; 

  到这里为止跟之前的一对一关联映射还看不出什么区别。区别在于Clazz类。Clazz类有一个List<Student>类型的students属性,用于记载这个班级对应的所有学生)。

private List<Student> students;

  那么,我们就可以预期,在接下来的selectClazzByIdselectStudentById方法中,结果中都需要返回Clazz和Student(或者Student的List)

2.4 Xml映射文件
2.4.1xml映射文件——ClazzMapper.xml:

  定义了一个selectClazzById方法。这里还是通过clazz的id查询班级信息,但是不同于一对一映射中的CardMapper.xml,这里希望查询到的是班级和学生的信息,所以这里更类似于上面的PersonMapper.xml。
  同样是先通过clazz的id查询到tb_clazz,然后映射成为Clazz对象。然后直接还是通过原来的这个clazz的id,通过调用接下来要讲到的StudentMapper.xml中的selectStudentByClazzId方法找到对应的Student的数据并封装成一个数据列表。
  这里和一对一中的PersonMapper.xml不同的地方在于它是沿用clazz的id进行查询,而不是像PersonMapper那样利用person的id查询到person的clazz_id,然后再利用clazz_id查询出clazz。并且这里由于是一对多,得到的是一个列表。

2.4.2 xml映射文件——StudentMapper.xml:

  定义了selectStudentById方法和selectStudentByClazzId方法。这里先说后面一个方法。因为ClazzMapper.xml会调用这个方法。这个方法看起来复杂(需要查询另外一张数据表),但是其实很简单。因为我们在上面的数据表关联中已经将clazz_id,和tb_clazz中的id进行关联。换句话说,通过tb_clazz中的id来查询Student数据就相当于是根据clazz_id来查询Student数据。所以:

SELECT * FROM tb_student WHERE clazz_id = #{id}

  这个方法其实在StudentMapper.xml中不是一个关键的方法,更像是ClazzMapper.xml中的selectClazzById方法所需要的一个步骤。上面也已经提到过selectClazzById中原本就能实现找到Clazz,但是为了再显示出Student才需要引用到selectStudentByClazzId这个方法。

  StudentMapper.xml中关键的方法是selectStudentById方法。
在selectStudentById方法中,希望通过学生id来查询到学生对象和班级对象。首先,如果使用SELECT * from tb_user where id= #{id}可以查询出来Student对象。
  但是这里需要将查到的student的clazz_id对应的班级的信息也都展示到结果中,所以还需要同时找到这个class对象。所以变成

    SELECT * FROM tb_clazz c,tb_student s
     WHERE c.id = s.clazz_id
      AND s.id = #{id}

  然后分别映射将结果封装到Clazz和Student对象中。

3、多对多关联映射

3.1 数据表:

tb_usertb_ordertb_article 。这里虽然说是多对多的关联映射,但是同时也存在一对多的关联映射。以及一个中间表tb_item

tb_user---一对多---> tb_order <---多对多---> tb_article

3.2 数据表关联:

  在数据库中构建数据表的时候,外键在多方
在tb_order表中新增一栏user_id,和tb_user中的id进行关联:

FOREIGN KEY(user_id) REFERENCES tb_user(id);

  但是在多和多关联映射下,不需要再表中添加新的关联栏。多对多可以通过构建一个中间表来维护关系。例如订单(tb_order)和商品(tb_article)的多对多关系,这时候可以使用中间表的订单id(order_id)作为外键来参照订单表的id,中间表的商品id(article_id)作为外键来参照商品表的id。这个表tb_item是不能够单独存在的,而要依赖于订单和商品存在

3.3 类关联:

  需要建立三个类:UserOrderArticle这三个。
  虽然创建了一个中间表,但是这个中间表不需要对应的类。

  使用新的表进行映射后,还需要在对应的类中添加相应的属性,在订单Order类中添加商品属性(List<Article> articles),而商品Article类中添加订单属性(List<Order> order)。此外,上面说过User和Order还存在一对多的关系,所以还需要在Order中添加一个User属性。Order类新增属性如下:

private User user;
private List<Article> articles;
3.4 XML 映射文件
3.4.1 xml映射文件——UserMapper.xml:

  这里定义了selectUserById方法,希望通过User的id查询到user对象,以及该对象所具有的所有订单。这还是上面的一对多的范畴。查询结构要求显示User和相关的Order对象。而要获取Order对象同样需要在OrderMapper.xml中的selectOrderByUserId中进行实现。这很容易实现。

3.4.2 xml映射文件——OrderMapper.xml:

  定义了selectOrderByIdselectOrderByUserId方法。
  selectOrderByUserId在3.4.1中需要利用到。
  而selectOrderById同样要一起找到tb_user表和tb_order表的数据。但是这里还需要调用ArticleMapper.xml中的selectArticleByOrderId方法,也就是说最后还需要显示所有的商品出来。

3.4.3 xml映射文件——ArticleMapper.xml:

  多对多很复杂,但是查询看起来确实比较简单,利用了子查询。在ArticleMapper.xml中,selectArticleByOrderId

    SELECT * FROM tb_article WHERE id IN(
        SELECT article_id FROM tb_item WHERE order_id = #{id}
    )

  可以看到,在这里才利用了tb_item这个表,先通过order_id查询到所有的article_id

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容