Mybatis学习——传入非标准数据,表单项的连接以及一对多与多对一详解

Mybatis学习——传入非标准数据,表单项的连接以及一对多与多对一详解

在先前的博客中,我们讨论了如何在Mapper.xml中配置集中常见的SQL语句,但有心的同学可能会发现之前提到的SQL语句都是些很基础的增删改操作,涉及到的传入参数类型要么是单一变量,如id;要么是引用类型中的参数是基本类型,如User类对象。结果类型也同样如此。

那么如果传入的参数类型,以及结果集对象稍微复杂一些时或者不那么标准时该怎么处理呢?这也是本篇文章所总结的内容。

参数集为非标准数据

首先需要说明的是,传入非标准数据是值既非标基础数据类型也非pojo中的引用类型。常见的例子有,希望通过分页查询数据;用户指定属性表单查询。这里仅对如何分页查询数据做一个简单的应用分析。更具体的分析待上手具体项目后再做总结。

分页查询数据

分页查询数据最重要的两个参数是startsize。前者指定了查询的开始id(不包括该id),后者指定从查询id开始,期望查询的个数,对应的sql语句如下:

select * from user limit 2,2  #表示查询user表 id=2开始,查询2个,最终查到了id=3以及id=4的数据项

因此,可以在UserMapper.xml中配置如下的信息(UserMap作结果集映射)

<select id="getUserByPage" parameterType="map" resultMap="UserMap">
  select * from Mybatis.user limit #{start},#{size}
</select>

<resultMap id="UserMap" type="User">
  <!--        <result column="id" property="id"/>-->
  <!--        <result column="name" property="name"/>-->
<result column="pwd" property="password"/>

有了上述的sql标签,接下来要考虑的便是如何在传参的时候让sql语句知道传入的两个数据哪个数据是start,哪个数据是size呢?这里有两种解决方案:

  • 解决方案一:在UserMapper接口中定义方法时,设置传入参数为map类型,并且规定传入数据时传入的map中必须包含有startsize的key值:具体代码如下

    // 接口中的方法
    List<User> getAllUsers(Map map);
    
    // 测试时传入数据
    Map<String, Integer> map = new HashMap<>();
    map.put("start", "2");
    map.put("size", "2");
    List<User> users = mapper.getUserByPage(map);
    
  • 解决方案二:在UserMapper接口中直接定义传入两个参数,同时使用@Param注解,告诉Mybatis该参数应当对应的sql语句中的参数,例如:

    // 接口中的方法
    List<User> getAllUsers(@Param("start")int start, @Param("size")int size);
    
    // 测试方法的传参形式
    List<User> users = mapper.getUserByPage(22);
    
    • 使用这种方法时,相当于在定义接口方法时告诉了Mybatis,第一个参数对应于sql语句中的#{start},第二个参数对应#{size}。在后续的项目中使用这种方法更加频繁,因为可以预想得到,使用这种方法不需要构建map容器,更加快速有效。

结果集为非标准数据

pojo中的大部分类中的参数类型都是基本数据类型,然而如果某些类中的参数也是引用类型时该怎么办呢?

首先需要说明的是,在pojo中stutent类中有三个属性,分别是id,name,teacher(引用类型),teacher类中也有三个属性分别是id,name,List<Student>

这里就以小狂神中的一对多和多对一的例子作为例子,具体分析这种自定义操作应当如何实现。

一对多

顾名思义,一对多就是一个实体类在可能对应着多个实体类。最典型的例子便是一个老师对应多个学生。在教务管理系统中,数据库中保存了有所有学生,老师的信息。

其中学生信息除了包含有idname外还可能因为被分配一个导师而存在teacherId项。通常,这种情况在数据库中会使用foreign key引用老师的id。现在有个需求:在查询老师信息的同时,返回该老师负责的所有学生的姓名

要解决上述问题,首先考虑如何书写sql语句。显然,这需要查询两个表,同时根据外键将表项连接起来,于是可以得到如下的sql语句:

select t.id tid, t.name tname, s.name sname
from student s, teacher t
where t.id = ?

有了sql语句便可以以此为模板,在xml中配置标签sql语句

<select id="getTeacherById" resultMap="TeacherStudentsMap">
	select t.id tid, t.name tname, s.name sname
	from student s, teacher t
	where t.id = #{tid}
</select>

<resultMap id="TeacherStudentsMap" type="teacher">
  <id property="id" column="tid"/>
  <id property="name" column="tname"/>
  <collection property="students" ofType="student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
  </collection>
</resultMap>

可以发现,一对多查询的关键在于结果集映射。分析上述resultMap的构造可以发现,其返回类型是teacher,同时由于teacher中存在一个容器,因此使用collection标签,声明其对应于teacher中的students属性,以及容器中存放类型为ofType="student"

最后再将查询结果数据中的column映射进容器中的每一个对象实例中。

⭐️ 需要说明的是,这里大量使用别名,因此propertycolumn的映射关系需要完全手动进行。查询结果中所期望包含的数据就一定要在sql语句中查询,同时也需要在resultMap中映射。没有映射的结果在返回打印时会显示null或者0

多对一

与一对多类似,多对一考虑的主体是学生,基于上述内容,再考虑一个需求:查询所有学生,返回学生的所有数据,包括老师信息。

同样考虑sql语句

select s.id sid, s.name sname, t.id tid, t.name tname
from student s,teacher t
where s.tid=t.id

以及xml中配置的sql标签

<select id="getStudents" resultMap="StudentsTeacherMap">
	select s.id sid, s.name sname, t.id tid, t.name tname
	from student s,teacher t
	where s.tid=t.id
</select>

<resultMap id="StudentsTeacherMap" type="student">
  <id property="id" column="sid"/>
  <id property="name" column="sname"/>
  <association property="teacher" javaType="teacher">
    <id property="id" column="tid"/>
    <id property="name" column="tname"/>
  </association>
</resultMap>

此时,结果返回类型为student,同时由于student类中没有涉及到容器,仅仅只有teacher一个引用类型,因此这里使用association来做类的装载,其属性数据的映射类似于一对多。

小结

本博客分析了Mybatis传入数据为非单个基本数据类型,以及返回结果pojo类中存在引用类型以及容器类型时涉及到的多对一和一对多的情况。

关于传入数据为非单个基本数据类型时,考虑要么使用map集合,要么使用注解标识。其中后者由于其简便性在实际开发中使用较多。

关于多对一和一对多,两者的主要区别在于xml中配置结果集映射时有些许不同,具体的:

  • 如果返回pojo类中存在容器类,则使用collection+ofType+result来实现映射

  • 如果返回pojo类汇总存在单个引用类型,则使用association+javaType+id来实现

    最后需要注意的是,对于期望展现出来的数据都应当做结果集映射,否则打印结果为0或null。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值