时间:2023-03-05 12:22:16 | 栏目:JAVA代码 | 点击:次
在开发中,可能会遇到一对多的关系,这个时候,一条sql语句就难以胜任这个任务了。只能先执行一条sql,然后根据返回的结果,再做一次sql关联查询,这个时候,使用mybatis的collection就可以实现。
如果第一次查询返回的是一个list集合,那么,后续的查询就是一个for循环。所以不使用collection的做法,在java语言中,就要分两次查询。一般而言,我们的列表查询都是分页查询,所以集合数据不会太大,第二次for循环查询效率还好。
下面介绍mybatis使用collection嵌套查询解决这个问题。这里为了简单,以员工与部门的关系来做这个实验,其实员工与部门的关系还应该使用一个中间表来关联,这里只用两张表。
表结构与数据如下所示:
数据:
这里采用maven构建springboot+mybatis-plus+mysql工程。
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
定义的实体:
员工信息:
package com.xxx.springboot.mybatis.domain; import java.util.List; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @Data @TableName("xx_emp") public class Employee { private Integer id ; private String name ; private int age ; private List<Department> depts ; }
部门信息
package com.xxx.springboot.mybatis.domain; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @Data @TableName("xx_dept") public class Department { private Integer id ; private String name ; private Integer userId ; }
Mapper接口
package com.xxx.springboot.mybatis.mapper; import org.apache.ibatis.annotations.Mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.xxx.springboot.mybatis.domain.Department; import com.xxx.springboot.mybatis.domain.Employee; @Mapper public interface EmpMapper extends BaseMapper<Employee>{ Employee queryByName(String name); Department queryByUserId(Integer userId); }
EmpMapper.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.xxx.springboot.mybatis.mapper.EmpMapper"> <resultMap id="empMap" type="com.xxx.springboot.mybatis.domain.Employee" > <id column="id" property="id" /> <result column="name" property="name" /> <result column="age" property="age" /> <collection property="depts" javaType="java.util.ArrayList" ofType="com.xxx.springboot.mybatis.domain.Department" select="com.xxx.springboot.mybatis.mapper.EmpMapper.queryByUserId" column="{userId=id}"></collection> </resultMap> <resultMap id="deptMap" type="com.xxx.springboot.mybatis.domain.Department"> <id column="id" property="id"/> <result column="name" property="name"/> <result column="user_id" property="userId"/> </resultMap> <select id="queryByName" resultMap="empMap"> SELECT * FROM xx_emp WHERE name = #{name} </select> <select id="queryByUserId" resultMap="deptMap"> SELECT * FROM xx_dept WHERE user_id = #{userId} </select> </mapper>
测试类:
package com.xxx.springboot; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.xxx.springboot.mybatis.domain.Employee; import com.xxx.springboot.mybatis.mapper.EmpMapper; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class MyBatisTest { @Autowired private EmpMapper empMapper; @Test public void testEmpQuery() { Employee emp = empMapper.queryByName("aa"); System.out.println(emp); } }
运行单元测试,打印信息如下:
这个程序,在第一次根据名称查询员工信息之后,返回id=1,name=aa,age=18,接着,根据id=1 查询了部门表,其实这里的id=1,作为参数传入部门表中,就成了user_id对应的参数,然后就查询出了两个部门记录id=1,id=3,最后打印的员工信息里面,depts就是一个集合。
使用这个嵌套查询,需要注意的是collection有如下属性:
property 实体中对应的属性,这里是depts。 javaType 实体属性的类型,这里是一个集合,所以使用java.util.ArrayList表示。 ofType 集合范型中的类型,这里是部门信息,对应java类Department select 嵌套子查询的ID column 这里最关键,也比较难理解,默认一个参数,可以直接写column = "id",最后根据参数类型匹配。这里其实是传入子查询中的参数,也就是子查询的关联属性user_id对应的参数值,在collection这里就是主sql中查询出来的列值,如果这里id有了别名,比如emp_id,这里就应该写column = "emp_id"。还有一种写法,通过大括号来表示,这种写法可以传入多个参数(多个参数用逗号隔开)。对于本示例而言,正确的写法就是column={userId=id},userId对应 queryByUserId查询语句中 SELECT * FROM xx_dept WHERE user_id = #{userId} 参数userId。id就是主sql查询出来的列id值,就是xx_emp对应的id列值。
我个人在使用collection的时候,大概明白这种嵌套查询的作用,但是就是不明白,怎么传递参数,后来看过一些例子,原来主要点就在column属性这里。