阿里P7JAVA大牛带你一起来看MyBatis(六)

作者: 5f1df32e8c44 | 来源:发表于2018-01-24 19:40 被阅读53次

    注意:一对一表的设计中,为了大家更直观地观察,我们采用的是在主表的一方加外键,实际上应该在从表中加外键,不过不影响演示效果】

    现在我们已经能够使用MyBatis对数据库进行一些基本的操作,包括XML和Annotation的两种方式,以及如何使用缓存对查询到的结果进行保存和调用等。

    那这一章咱们讨论啥呢?好像又蒙圈了,似乎没啥好学的了,但是又感觉不踏实,总觉得还有很多没了解。今天就先来讨论其中一点,咱们想想,之前所有的操作是不是都用的一张表?也就是说CRUD都是基于t_users表进行的,那假设有多张表呢?表与表之间是会存在关系的,比如一对一,一对多和多对多,这时候使用MyBatis该如何对多张表进行操作?

    一对一的关系

    【注意:一对一表的设计中,为了大家更直观地观察,我们采用的是在主表的一方加外键,实际上应该在从表中加外键,不过不影响演示效果】

    我们得先想一个“一对一”的关系,比如“人”和“身份证”之间就是“一对一”的关系。当然,不去考虑一个人有两张身份证的特殊情况,我们指的是绝大多数人,于是需要设计两张表t_person和t_identitycard,t_person表为主,identity表为从,在主的一方加外键标明两表之间的关系。至于表设计的规范这里我就不作详细解释咯,不清楚的同学可以找下相关的资料。

    大家还记得之前一张表搭建环境的步骤吗?这里还是一样,我们一步步来,不过能文字带过的步骤咱们就不截图咯,之前写了很多次,应该都很熟练了吧?

    1)创建数据表t_identity和t_person

    下图是两张表的sql创建语句以及外键约束

    然后我们向两张表中添加几条数据,这是t_identitycard表

    这是t_person表

    可以看出,每个人都有一个c_id,对应t_identitycard表中的一条条记录。

    2)创建Java工程"ES9D_MyBatis6",并导入相关的jar包

    3)创建t_identitycard和t_person表对应的实体类

    在设计Person类的时候要注意,t_person表的外键体现在用一个IdentityCard类类型的属性。

    4)创建SqlMapConfig.xml文件

    5)创建xxxMapper.xml文件

    将其交给SqlMapConfig.xml文件管理,比如personMapper.xml和identitycardMapper.xml两个文件

    6)根据SqlMapConfig.xml文件得到一个session,就可以进行相应的操作了

    看上去和之前的步骤没差别,就是多了一个表而已。当然,对于单表的操作肯定是没区别的,但是如果同时涉及到两张表呢?我们这里只讨论查询的情况,至于增删改实际上和之前没太大区别,只要不违反外键约束即可。

    【需求】查询出p_id为1的人的全部信息(包括姓名,身份证号码)

    如果是单纯查询p_id为1的人的姓名,那么就是之前的单表t_person操作,但是还需要身份证号码,这就涉及到另外一张表t_identitycard。归根结底,咱们需要写sql语句,因为最终是需要在xxxMapper.xml文件中进行sql语句的编写,那不妨先把sql语句写出来,看看能否执行成功,有两种查询方式,一种是两张表联合查询,另外一种是分两次查询。

    a.分两次查询

    select * from t_person where p_id=1;

    根据上面的查询结果可以得到c_id为1,然后再去查另外一张表

    select * from t_identitycard where c_id=1;

    b.一次查询

    select * from t_person p,t_identitycard c where p.c_id=c.c_id and p.p_id=1;

    在sql中执行结果

    7)好了,sql语句是没问题了,那接下来怎么做?

    要朝这java程序员发展或者真心有兴趣的。可以找我要一些java的学习视频Java学习交流群:450936584,这个是免费的,希望同学找我要的时候不要有理所应当的态度,毕竟都是我的心血,希望你是真的有一颗想要学好java的心,我也会尽所能的去帮助你成为一名优秀的程序员

    是不是得去完成xxxMapper.xml文件了?因为其中还没有内容,关键在于xxxMapper.xml文件的编写,我们可以创建两个Mapper.xml文件,也可以用一个Mapper.xml文件,因为每个标签都有唯一一个id,所以不用担心冲突的问题,大家想想是不是这个道理?为了方便管理,这里我就创建一个personMapper.xml文件。

    8)两次查询select标签写法

    根据前面的经验,咱们先把两个select标签写好,如下图所示

    上面两个select标签的含义很容易理解,接下来要考虑的就是两个数据表的字段名和实体类的属性名是否一致,如果不一致,需要使用resultMap标签进行映射或者使用别名的方式,这块咱们在第(五)章详细介绍过。

    可以发现,t_identitycard表和IdentityCard实体类没有问题。

    但是t_person表和Person实体类却有一个字段名和属性名不一致,那咱们就使用resultMap来映射,如下图所示

    在resultMap标签中,咱们没有使用id和result标签,因为其他两个属性名和字段名是一致的,只需要对不一致的进行映射,这里使用的是association标签,property和column两个属性不用多说咯,前面有介绍过,最主要的是select属性,它的值与第二个select标签的id值对应,啥意思?试想一下,在实体类Person中,咱们维护了一个IdentityCard对象,而在t_person表中,咱们记录的是c_id外键,这两者名称不一致,可以通过property属性和column属性映射,关键是它俩的值类型也不一样,一个是对象类型,一个是varchar类型,得转换,所以这里用select属性表示实体类Person的属性identityCard的值是从另外一个地方引用过来的,也就是把第二个select标签查询的结果赋值给identityCard对象。

    接下里咱们测试一下

    结果正是我们想要的,一起来分析一下,代码中执行的是id值为getPersonByTwice的标签,返回值类型是Person。传入id值为1,会得到t_person表中id为1的记录数据,有p_id=1,p_name=zhangsan,c_id=1,注意,因为实体类中属性identityCard类型为IdentityCard类型,而c_id为String类型,所以不能直接赋值。根据association标签的select属性,此时将c_id=1的结果赋值给第二个select查询标签,第二个select查询标签查询出来的结果是c_id=1,c_num=623368199305069909并封装成IdentityCard对象赋值给Person类的identityCard属性。整个过程中,我们只调用了第一个select标签,而第二个select标签好像是自动执行的,这就和association标签有关,association通常就用于这种一对一的关系中。因为在一对一的关系中,数据表之间的体现是主外键关系,为了不丢关系,所以在实体类之间的体现就是在主类中维护一个从类的对象属性,比如在Person类中维护一个IdentityCard对象。那这样在查询主表全部信息时,需要将从表的信息也查询出来,所以数据表外键的字段名称和实体类属性对象的名称就不能用result标签维护,倘若使用result标签维护,那么得出的结果就是null,需要用select属性去引用另外一个select标签查询出来的结果,好好体会一下,下面我们使用联合查询一次得到结果,看mapper文件怎么写,正好加深一下association标签的理解。

    9)一次查询select标签写法

    先来看下一次查询的sql语句

    select * from t_person p,t_identitycard c where p.c_id=c.c_id and p.p_id=1;

    有了这个语句就好办了,动手写select标签

    写完之后又懵逼了,这是啥?抽根烟冷静下,原来这是联合查询的sql语句,然后呢?去测试一把?好像总觉得哪边不对劲,先不管了,就要测试一下

    于是测试代码来了

    运行是成功了,但是有个问题,Person类中的identityCard对象属性的值为null,为啥没值?这时候咱们就需要想想数据表字段名和实体类属性名是否一致,经过前面的检查,identitycard是没问题的,问题在于person,要想解决就得去使用resultMap映射一把。映射的过程比较简单,无非几个标签的使用,这里我们先不用association标签,直接用普通属性的result标签,然后分别把property和column填上,按理说这样就做了一个映射,就解决了名称不一致的问题。

    那就再来运行看看

    依旧如此,为何?名称一致性的问题是解决了,还是回归到类型的问题,一个是对象类型,一个是varchar类型,怎么赋值呢?所以为null也合情合理,咋办?把result标签改成association标签,说改就改。

    运行看结果

    发现报了一个这样的错

    这时候需要将javaType显示的写出,javaType="com.es9d.domain.IdentityCard",至于具体原因,我们后面介绍typeHandler的时候会详细说明,这里大家就理解和上面的二次sql查询做一个对比理解,之前需要指定一个select属性,而这块也同样要指定,并且需要将表字段和实体类属性对应的关系写出来,如下图所示

    此时咱们再运行看下

    好像有点结果了,不过前面两个属性没有值?原因是啥?也是需要将对应关系显示写出来

    最后咱们再运行看下

    好了,到这里一次查询的select标签写法已经完成,主要需要注意的是association标签的用法,一方面需要指定javaType值,另外一方面需要将数据表字段名和实体类属性名一一对应关系显示写出。接下来章节我们就讨论一对多的关系怎么写mapper文件。

    相关文章

      网友评论

        本文标题:阿里P7JAVA大牛带你一起来看MyBatis(六)

        本文链接:https://www.haomeiwen.com/subject/ghqpaxtx.html