MyBatis复杂sql:多对一处理(association)和一对多(collection)

多对一(association标签)

  • 老师和学生的例子
  • 以学生为出发点,就是一个多对一的例子,即多个学生关联一个老师!

首先搭建数据库

CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, '羊羊');

CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8


INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小羊', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小锅', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小虎', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小狗', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小明', '1');

利用lombok简化代码

1、Lombok

  • lombok是一个可以帮助我们简化java代码编写的工具类,尤其是简化javabean的编写,即通过采用注解的方式,消除代码中的构造方法,getter/setter等代码,使我们写的类更加简洁,当然,这带来的副作用就是不易阅读…
  • lombok注解解释:https://www.cnblogs.com/heyonggang/p/8638374.html,当然大家也可以自行百度

2、引入Lombok的Maven依赖

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <version>1.16.10</version>
</dependency>

3、在代码中增加注解

@Data //GET,SET,ToString,有参,无参构造
public class Teacher {
   private int id;
   private String name;
}
@Data
public class Student {
   private int id;
   private String name;
   //多个学生可以是同一个老师,即多对一
   private Teacher teacher;
}

4、编写实体类对应的Mapper接口

public interface StudentMapper {
}
public interface TeacherMapper {
}

5、编写Mapper接口对应的 mapper.xml配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yang.mapper.StudentMapper">

</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yang.mapper.TeacherMapper">

</mapper>

复杂查询,获取所有学生及对应老师的信息

  • 两种方法实现
  • 按查询嵌套处理(像SQL中的子查询)
  • 按结果嵌套处理(像SQL中的联表查询)

1、给StudentMapper接口增加方法

public List<Student> getStudents();   //查询嵌套处理
public List<Student> getStudents2();  //结果嵌套处理

2、编写对应的Mapper文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yang.mapper.StudentMapper">

   <!--
   查询嵌套处理
   -->
   <select id="getStudents" resultMap="StudentTeacher">
    select * from student
   </select>
   <resultMap id="StudentTeacher" type="Student">
       <!--association关联属性 property属性名 javaType属性类型 column在多的一方的表中的列名-->
       <association property="teacher"  column="tid"javaType="Teacher" select="getTeacher"/>
   </resultMap>
   <!--
   这里传递过来的id,只有一个属性的时候,下面可以写任何值
   association中column多参数配置:
       column="{key=value,key=value}"
       其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。
   -->
   <select id="getTeacher" resultType="teacher">
      select * from teacher where id = #{id}
   </select>
   
	<!--
	按查询结果嵌套处理
	-->
	<select id="getStudents2" resultMap="StudentTeacher2" >
	  select s.id sid, s.name sname , t.name tname
	  from student s,teacher t
	  where s.tid = t.id
	</select>
	
	<resultMap id="StudentTeacher2" type="Student">
	   <id property="id" column="sid"/>
	   <result property="name" column="sname"/>
	   <!--关联对象property 关联对象在Student实体类中的属性-->
	   <association property="teacher" javaType="Teacher">
	       <result property="name" column="tname"/>
	   </association>
	</resultMap>

</mapper>

3、记得注册Mapper

4、注意点说明:

<resultMap id="StudentTeacher" type="Student">
   <!--association关联属性 property属性名 javaType属性类型 column在多的一方的表中的列名-->
   <association property="teacher"  column="{id=tid,name=tid}"javaType="Teacher" select="getTeacher"/>
</resultMap>
<!--
这里传递过来的id,只有一个属性的时候,下面可以写任何值
association中column多参数配置:
   column="{key=value,key=value}"
   其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。
-->
<select id="getTeacher" resultType="teacher">
  select * from teacher where id = #{id} and name = #{name}
</select>

5、测试

@Test
public void testGetStudents(){
   SqlSession session = MybatisUtils.getSession();
   StudentMapper mapper =session.getMapper(StudentMapper.class);

   List<Student> students = mapper.getStudents();

   for (Student student : students){
       System.out.println(
               "学生名:"+ student.getName()
                       +"\t老师:"+student.getTeacher().getName());
  }
}

@Test
public void testGetStudents2(){
   SqlSession session = MybatisUtils.getSession();
   StudentMapper mapper =session.getMapper(StudentMapper.class);

   List<Student> students = mapper.getStudents2();

   for (Student student : students){
       System.out.println(
               "学生名:"+ student.getName()
                       +"\t老师:"+student.getTeacher().getName());
  }
}

一对多的处理

  • 老师和学生的例子
  • 以老师为出发点,就是一个多对一的例子,即一个老师关联多个学生!

环境相同,使用两种方法分别实现
按结果嵌套处理

1、TeacherMapper接口编写方法

//获取指定老师,及老师下的所有学生
public Teacher getTeacher(int id);

2、编写接口对应的Mapper配置文件

<mapper namespace="com.yang.mapper.TeacherMapper">

   <!--
   思路:
       1. 从学生表和老师表中查出学生id,学生姓名,老师姓名
       2. 对查询出来的操作做结果集映射
           1. 集合的话,使用collection!
               JavaType和ofType都是用来指定对象类型的
               JavaType是用来指定pojo中属性的类型
               ofType指定的是映射到list集合属性中pojo的类型。
   -->
   <select id="getTeacher" resultMap="TeacherStudent">
      select s.id sid, s.name sname , t.name tname, t.id tid
      from student s,teacher t
      where s.tid = t.id and t.id=#{id}
   </select>

   <resultMap id="TeacherStudent" type="Teacher">
       <result  property="name" column="tname"/>
       <collection property="students" ofType="Student">
           <result property="id" column="sid" />
           <result property="name" column="sname" />
           <result property="tid" column="tid" />
       </collection>
   </resultMap>
</mapper>

3、将Mapper文件注册到MyBatis-config文件中

<mappers>
   <mapper resource="mapper/TeacherMapper.xml"/>
</mappers>

4、测试

@Test
public void testGetTeacher(){
   SqlSession session = MybatisUtils.getSession();
   TeacherMapper mapper =session.getMapper(TeacherMapper.class);
   Teacher teacher = mapper.getTeacher(1);
   System.out.println(teacher.getName());
   System.out.println(teacher.getStudents());
}

按查询嵌套处理

1、TeacherMapper接口编写方法

public Teacher getTeacher2(int id);

2、编写接口对应的Mapper配置文件

<select id="getTeacher2" resultMap="TeacherStudent2">
select * from teacher where id = #{id}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
   <!--column是一对多的外键 , 写的是一的主键的列名-->
   <collection property="students" javaType="ArrayList"ofType="Student" column="id" select="getStudentByTeacherId"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
  select * from student where tid = #{id}
</select>

3、将Mapper文件注册到MyBatis-config文件中

4、测试

@Test
public void testGetTeacher2(){
   SqlSession session = MybatisUtils.getSession();
   TeacherMapper mapper =session.getMapper(TeacherMapper.class);
   Teacher teacher = mapper.getTeacher2(1);
   System.out.println(teacher.getName());
   System.out.println(teacher.getStudents());
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java MyBatis中,一对多关系可以通过使用collection来实现。具体而言,MyBatis提供了两种方式来处理一对多关系:嵌套查询和嵌套结果。 1. 嵌套查询: 在嵌套查询中,我们可以通过执行额外的SQL语句来获取与主对象相关联的子对象集合。这需要在映射文件中定义一个额外的select语句,并使用association标签将其与主对象关联起来。然后,在主对象的映射文件中,使用collection标签指定子对象集合的属性名,并引用该额外的select语句。 例如,假设有两个表:Order(订单)和 OrderItem(订单项),一个订单可以包含多个订单项。那么可以按照以下步骤进行配置: a) 定义额外的select语句: ```xml <select id="getOrderItemsByOrderId" resultType="OrderItem"> SELECT * FROM order_item WHERE order_id = #{orderId} </select> ``` b) 在Order的映射文件中,使用collection标签引用该额外的select语句: ```xml <resultMap id="orderResultMap" type="Order"> <!-- 其他属性映射 --> <collection property="orderItems" resultMap="orderItemResultMap"/> </resultMap> ``` 2. 嵌套结果: 在嵌套结果中,我们可以通过一次查询将主对象及其关联的子对象一起加载到内存中。这需要在映射文件中定义一个resultMap,并使用association标签将主对象与子对象关联起来,然后使用collection标签指定子对象集合的属性名。 继续以上面的例子为例: a) 在Order的映射文件中,定义resultMap并使用associationcollection标签: ```xml <resultMap id="orderResultMap" type="Order"> <!-- 其他属性映射 --> <collection property="orderItems" ofType="OrderItem"> <id property="id" column="item_id"/> <!-- 其他属性映射 --> </collection> </resultMap> ``` b) 在查询语句中引用该resultMap: ```xml <select id="getOrderById" resultMap="orderResultMap"> SELECT * FROM orders WHERE order_id = #{orderId} </select> ``` 这样配置之后,当执行查询操作时,MyBatis会自动根据配置的方式加载主对象及其关联的子对象集合。 具体作用:通过使用collection实现一对多关系,可以方便地获取主对象关联的子对象集合,从而简化了数据查询和处理的过程。例如,在订单系统中,我们可以轻松地获取某个订单下的所有订单项,或者在商品系统中,获取某个分类下的所有商品列表等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值