MyBatis使用嵌套查詢collection和association的實現(xiàn)
1、目標(biāo)
本文的主要目標(biāo)是MyBatis使用collection標(biāo)簽完成一對多的嵌套查詢,使用association標(biāo)簽完成一對一的嵌套查詢
2、一對多的嵌套查詢用collection標(biāo)簽
2.1 多表查詢并且resultMap是數(shù)據(jù)庫的class表
create table `class` (
`id` int primary key auto_increment,
`name` varchar(100) not null,
`create_time` date not null
);
create table `stu` (
`id` int primary key auto_increment,
`name` varchar(100) not null,
`age` int not null,
`class_id` int not null
);
先在數(shù)據(jù)庫創(chuàng)建表class和stu,class是班級表,stu是學(xué)生表,stu學(xué)生表中包含class_id字段表示這個學(xué)生在哪個班級中
insert into `class`(`name`, `create_time`) values ('1班', now()), ('2班', now()), ('3班', now());
然后在class表中插入記錄
insert into `stu`(`name`, `age`, `class_id`) values ('張三1', 20, 1), ('李四1', 18, 1), ('王五1', 21, 1),
('張三2', 15, 2), ('李四2', 19, 2), ('王五2', 16, 2),
('張三3', 22, 3), ('李四3', 29, 3), ('王五3', 26, 3);
然后在stu表中插入記錄
@Data
public class Class {
private String id;
private String name;
private String createTime;
private List<Stu> stuList;
@Override
public String toString() {
return "Class{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", createTime='" + createTime + '\'' +
", stuList=" + stuList +
'}';
}
}
創(chuàng)建Class實體類,對應(yīng)class表的字段,其中多了一個字段是stuList這個list集合,因為一個班級包含了多個學(xué)生,這里是一對多的嵌套查詢因此用collection標(biāo)簽
@Data
public class Stu {
private Integer id;
private String name;
private Integer age;
private Integer classId;
@Override
public String toString() {
return "Stu{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", classId=" + classId +
'}';
}
}
創(chuàng)建Stu實體類,對應(yīng)stu表的字段
@Mapper
public interface ClassMapper {
Class getClass(@Param("className") String className);
}
創(chuàng)建ClassMapper的接口方法getClass,入?yún)⑹莄lassName,出參是一個Class班級對象,這個班級對象會封裝多個學(xué)生對象
<?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="org.apache.mybatisDemo.ClassMapper">
<resultMap id="classMap" type="org.apache.mybatisDemo.Class">
<id property="id" column="classId"/>
<result property="name" column="className"/>
<result property="createTime" column="create_time"/>
<collection property="stuList" javaType="java.util.List" ofType="org.apache.mybatisDemo.Stu">
<result property="id" column="stuId"/>
<result property="name" column="stuName"/>
<result property="age" column="age"/>
<result property="classId" column="class_id"/>
</collection>
</resultMap>
<select id="getClass" resultMap="classMap">
select c.id classId, c.name className, c.create_time, s.id stuId, s.name stuName, s.age, s.class_id
from `class` c inner join `stu` s on c.id = s.class_id
where c.`name` = #{className}
</select>
</mapper>
sql使用多表查詢,resultMap是返回值的類型,使用collection標(biāo)簽封裝多個Stu學(xué)生對象,collection標(biāo)簽中javaType指定是List集合類型,ofType指定List集合的泛型類型
注意:
(1)
<id property="id" column="classId"/> <result property="name" column="className"/> <result property="createTime" column="create_time"/>
resultMap中除了collection的更新字段至少有1個,比如這里我更新了3個字段
如果除了collection沒有更新字段,會拋出異常,具體參考我寫的博客:MyBatis嵌套查詢collection報錯:org.apache.ibatis.exceptions.TooManyResultsException
(2)sql查詢的字段如果重復(fù)名字的要取別名,如果不取別名resultMap直接用c.id,MyBatis底層不會將這個字段作為查詢字段,因為它識別不了c是哪張表
<mappers>
<mapper resource="mybatis/ClassMapper.xml"/>
</mappers>
mybatis-config.xml文件中設(shè)置mapper標(biāo)簽是ClassMapper.xml,因此可以掃描到這個xml文件
@Test
public void f1() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
ClassMapper mapper = sqlSession.getMapper(ClassMapper.class);
Class cls = mapper.getClass("2班");
System.out.println(cls.toString());
}
}
測試這個接口方法

測試結(jié)果返回一個Class班級對象,這個對象包含id=2,name=2班,createTime,stuList是一個list集合,它封裝了多個Stu學(xué)生對象
2.2 多表查詢并且resultMap是自定義VO類ClassVO
那resultMap返回值類型必須是數(shù)據(jù)庫表對應(yīng)的實體類嗎?不一定,返回值類型可以是自定義類比如VO
@Data
public class ClassVO {
private String id;
private List<Stu> stuList;
@Override
public String toString() {
return "ClassVO{" +
"id='" + id + '\'' +
", stuList=" + stuList +
'}';
}
}
自定義VO類ClassVO包含的字段只有id和stuList這個list集合
@Mapper
public interface ClassMapper {
ClassVO getClassVO(@Param("className") String className);
}
創(chuàng)建接口方法,返回值類型是自定義ClassVO類
<?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="org.apache.mybatisDemo.ClassMapper">
<resultMap id="classVOMap" type="org.apache.mybatisDemo.ClassVO">
<id property="id" column="classId"/>
<collection property="stuList" javaType="java.util.List" ofType="org.apache.mybatisDemo.Stu">
<id property="id" column="stuId"/>
<result property="name" column="stuName"/>
<result property="age" column="age"/>
<result property="classId" column="class_id"/>
</collection>
</resultMap>
<select id="getClassVO" resultMap="classVOMap">
select c.id classId, c.name, c.create_time, s.id stuId, s.name stuName, s.age, s.class_id
from `class` c inner join `stu` s on c.id = s.class_id
where c.`name` = #{className}
</select>
</mapper>
這個接口方法的xml對應(yīng)的返回值類型是type=“org.apache.mybatisDemo.ClassVO”
注意:
(1)resultMap中除了collection的更新字段至少有1個
(2)sql查詢的字段如果重復(fù)名字的要取別名
@Test
public void f2()throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
ClassMapper mapper = sqlSession.getMapper(ClassMapper.class);
ClassVO classVO = mapper.getClassVO("2班");
System.out.println(classVO.toString());
}
}
測試getClassVO方法,返回值是一個ClassVO對象

測試結(jié)果是返回一個ClassVO對象,它包含id=2,stuList這個list集合,它包含了3個Stu學(xué)生對象
結(jié)論:resultMap返回值類型不一定是數(shù)據(jù)庫表對應(yīng)的實體類,可以是自己定義的類
2.3 單表查詢并且resultMap是自定義VO類ClassVO
可以單表查詢stu學(xué)生表然后resultMap可以映射嗎?可以,不過除了resultMap中除了collection必須至少有1個字段更新
@Mapper
public interface ClassMapper {
ClassVO getClasVOBySingleTable(@Param("classId") Integer classId);
}
創(chuàng)建一個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="org.apache.mybatisDemo.ClassMapper">
<resultMap id="ClasVOBySingleTableMap" type="org.apache.mybatisDemo.ClassVO">
<id property="id" column="class_id"/>
<collection property="stuList" javaType="java.util.List" ofType="org.apache.mybatisDemo.Stu">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="classId" column="class_id"/>
</collection>
</resultMap>
<select id="getClasVOBySingleTable" resultMap="ClasVOBySingleTableMap">
select * from stu where stu.class_id = #{classId}
</select>
</mapper>
mapper.xml文件中sql是單表查詢,也可以進(jìn)行resultMap的字段賦值
注意:
(1)resultMap中除了collection的更新字段至少有1個
(2)sql查詢的字段如果重復(fù)名字的要取別名
@Test
public void f3() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
ClassMapper mapper = sqlSession.getMapper(ClassMapper.class);
ClassVO classVO = mapper.getClasVOBySingleTable(2);
System.out.println(classVO.toString());
}
}
調(diào)用getClasVOBySingleTable方法會返回ClassVO對象

測試結(jié)果是單表查詢,也可以返回一個ClassVO對象,它包含id=2,stuList是list集合,它包含3個Stu學(xué)生對象
結(jié)論:單表查詢stu學(xué)生表然后resultMap可以映射
2.4 單表查詢并且resultMap是自定義VO類ClassVO,返回值是List類型
@Mapper
public interface ClassMapper {
List<ClassVO> getClassVOList();
}
mapper接口方法的返回值是list集合
<select id="getClassVOList" resultMap="ClasVOBySingleTableMap"> select * from stu </select>
mapper.xml文件中單表查詢,resultMap仍然是2.3中的resultMap即ClasVOBySingleTableMap,因為返回值類型list集合的泛型還是ClassVO類
@Test
public void f4() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
ClassMapper mapper = sqlSession.getMapper(ClassMapper.class);
List<ClassVO> list = mapper.getClassVOList();
list.forEach(System.out::println);
}
}
測試:調(diào)用getClassVOList方法

測試結(jié)果是單表查詢返回stu學(xué)生表的所有記錄,指定resultMap,封裝了collection,因此會將相同class_id的多個Stu學(xué)生對象封裝到一個ClassVO對象,結(jié)果是返回3個ClassVO對象,每個ClassVO對象都封裝了3個Stu對象
結(jié)論:mapper接口方法的返回值是多個class_id的ClassVO對象用List集合,resultMap指定List集合的泛型,MyBatis會自動將相同class_id的Stu學(xué)生對象封裝到一個ClassVO對象中
2.5 多表查詢并且resultMap是數(shù)據(jù)庫的class表,返回值是List類型
@Mapper
public interface ClassMapper {
List<Class> getClassList();
}
返回值是List集合
<select id="getClassList" resultMap="classMap">
select c.id classId, c.name className, c.create_time, s.id stuId, s.name stuName, s.age, s.class_id
from `class` c inner join `stu` s on c.id = s.class_id
</select>
resultMap復(fù)用2.1的resultMap,因為返回值是list集合,它的泛型和2.1的返回值類型是相同的
@Test
public void f5() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
ClassMapper mapper = sqlSession.getMapper(ClassMapper.class);
List<Class> list = mapper.getClassList();
list.forEach(System.out::println);
}
}
調(diào)用getClassList方法

返回值是3個Class班級對象,每個Class班級對象都封裝了自己班的Stu學(xué)生對象
結(jié)論:mapper接口方法的返回值是多個class_id的Class班級對象用List集合,resultMap指定List集合的泛型,MyBatis會自動將相同class_id的Stu學(xué)生對象封裝到一個Class班級對象中
3、一對一的嵌套查詢用association標(biāo)簽
3.1 多表查詢,返回值是Stu學(xué)生對象
@Data
public class Stu {
private Integer id;
private String name;
private Integer age;
private Integer classId;
private Class stuClass;
@Override
public String toString() {
return "Stu{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", classId=" + classId +
", stuClass=" + stuClass +
'}';
}
}創(chuàng)建Stu實體類對象,多一個表中不存在的Class類型的stuClass對象,它表示這個學(xué)生屬于哪個班級,這里是一對一的嵌套查詢因此用association標(biāo)簽
@Mapper
public interface StuMapper {
Stu getStuById(@Param("stuName") String stuName);
}mapper接口方法是getStuById方法,返回值是Stu學(xué)生對象
<?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="org.apache.mybatisDemo.StuMapper">
<resultMap id="StuMap" type="org.apache.mybatisDemo.Stu">
<id property="id" column="stuId"/>
<result property="name" column="stuName"/>
<result property="age" column="age"/>
<result property="classId" column="class_id"/>
<association property="stuClass" javaType="org.apache.mybatisDemo.Class">
<id property="id" column="classId"/>
<result property="name" column="className"/>
<result property="createTime" column="create_time"/>
</association>
</resultMap>
<select id="getStuById" resultMap="StuMap">
select c.id classId, c.name className, c.create_time, s.id stuId, s.name stuName, s.age, s.class_id
from `class` c inner join `stu` s on c.id = s.class_id
where s.`name` = #{stuName}
</select>
</mapper>
mapper.xml文件多表查詢,resultMap的type是org.apache.mybatisDemo.Stu類型,其中stuClass屬性是Class班級類型,是一對一的嵌套查詢因此用association標(biāo)簽,association標(biāo)簽用javaType表示類型是org.apache.mybatisDemo.Class
<mappers>
<mapper resource="mybatis/BlogMapper.xml"/>
<mapper resource="mybatis/ClassMapper.xml"/>
<mapper resource="mybatis/StuMapper.xml"/>
</mappers>
mybatis-config.xml文件中注冊StuMapper.xml
@Test
public void f8() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
StuMapper mapper = sqlSession.getMapper(StuMapper.class);
Stu stu = mapper.getStuById("張三3");
System.out.println(stu);
}
}
調(diào)用mapper的getStuById方法

測試結(jié)果是返回一個Stu學(xué)生對象,它包含id=7,name=張三3,age=22,classId=3,stuClass屬性是一個Class班級對象,使用association標(biāo)簽封裝了這個Class班級對象
結(jié)論:一對一的嵌套查詢用association標(biāo)簽
3.2 多表查詢,返回值是List集合,泛型是Stu學(xué)生對象
@Mapper
public interface StuMapper {
List<Stu> getStuList();
}
返回值是List集合,泛型是Stu學(xué)生對象
<?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="org.apache.mybatisDemo.StuMapper">
<select id="getStuList" resultMap="StuMap">
select c.id classId, c.name className, c.create_time, s.id stuId, s.name stuName, s.age, s.class_id
from `class` c inner join `stu` s on c.id = s.class_id
</select>
</mapper>
mapper.xml的方法中resultMap指定StuMap,還是3.1中的resultMap,只需要指定List集合的泛型即可
@Test
public void f9() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
StuMapper mapper = sqlSession.getMapper(StuMapper.class);
List<Stu> stuList = mapper.getStuList();
stuList.forEach(System.out::println);
}
}
調(diào)用mapper的getStuList方法

測試結(jié)果是查詢得到9個Stu學(xué)生對象,每個學(xué)生對象都封裝了stuClass這個Class班級對象
結(jié)論:一對一的嵌套查詢用association標(biāo)簽,并且mapper接口方法返回值是List集合類型
到此這篇關(guān)于MyBatis使用嵌套查詢collection和association的實現(xiàn)的文章就介紹到這了,更多相關(guān)MyBatis 嵌套查詢collection和association內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Mybatis中collection和association的使用區(qū)別詳解
- mybatis利用association或collection傳遞多參數(shù)子查詢
- Mybatis之a(chǎn)ssociation和collection用法
- 在Mybatis中association標(biāo)簽多層嵌套的問題
- mybatis中一對一關(guān)系association標(biāo)簽的使用
- MyBatis中association的基本使用方法
- mybatis的association傳遞參數(shù)問題示例
- Mybatis中一對多(collection)和一對一(association)的組合查詢使用
- MyBatis的collection和association的使用解讀
- mybatis中association標(biāo)簽的使用解讀
- Mybatis的association使用子查詢結(jié)果錯誤的問題解決
相關(guān)文章
Java多例Bean的應(yīng)用場景-easyExcel導(dǎo)入
EasyExcel 是一個基于 Java 的簡單、省內(nèi)存的讀寫 Excel 的開源項目。這篇文章主要介紹了用easyExcel導(dǎo)入Java Bean的應(yīng)用場景,感興趣的朋友可以參考閱讀2023-04-04
mybatis條件構(gòu)造器(EntityWrapper)的使用方式
這篇文章主要介紹了mybatis條件構(gòu)造器(EntityWrapper)的使用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringBoot2零基礎(chǔ)到精通之?dāng)?shù)據(jù)庫專項精講
SpringBoot是一種整合Spring技術(shù)棧的方式(或者說是框架),同時也是簡化Spring的一種快速開發(fā)的腳手架,本篇我們來學(xué)習(xí)如何連接數(shù)據(jù)庫進(jìn)行操作2022-03-03
SpringMVC中redirect重定向(帶參數(shù))的3種方式
Spring MVC中做form表單功能提交時,防止用戶客戶端后退或者刷新時重復(fù)提交問題,需要在服務(wù)端進(jìn)行重定向跳轉(zhuǎn),本文主要介紹了SpringMVC中redirect重定向(帶參數(shù))的3種方式,感興趣的可以了解一下2024-07-07

