1 mybatis多表查询XML方式
1.1 一对一查询
1.1.1 表关系
一对一关系中,表关系由任意一方维护,以人和身份证为例,一个人对应一个身份证,一个身份证对应一个人。本案例中由身份证表维护表关系
1.1.2 需求
查询所有的身份证,并且要将身份证对应的人也查询出来
1.1.3 实现步骤
第一步:建表
DROP TABLE IF EXISTS `person`; CREATE TABLE `person` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(30) NOT NULL COMMENT '姓名', `age` int(11) NOT NULL COMMENT '年龄', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='用户表'; insert into `person`(`id`,`name`,`age`) values (1,'陈乔恩',39),(2,'钟汉良',44),(3,'林志颖',44),(4,'吴奇隆',48); DROP TABLE IF EXISTS `card`; CREATE TABLE `card` ( `id` int(11) NOT NULL AUTO_INCREMENT, `number` varchar(30) NOT NULL COMMENT '身份证号', `pid` int(11) NOT NULL COMMENT '所属用户', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='身份证表'; insert into `card`(`id`,`number`,`pid`) values (1,' 110101199003079008',1),(2,'110101199003079331',2),(3,' 11010119900307299X',3),(4,' 110101199003070791',4);
第二步:创建实体类
Person 人类
package cn.oldlu.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Person { private Integer id; private String name; private Integer age; }
Card 身份证类,因为需求是查询身份证,并且查询对应的人,所以应该是Card实体类中存放Perosn属性
package cn.oldlu.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class Card { private Integer id; private String number; private Person person; }
第三步:创建Dao接口
package cn.oldlu.dao; import cn.oldlu.domain.Card; import java.util.List; public interface CardDao { List<Card> findAll(); }
第四步:创建映射文件
resultMap的分析与编写
在src或resources目录创建CardMapper.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"> <!--namespace的值是UserDao的类全名--> <mapper namespace="cn.oldlu.dao.CardDao"> <resultMap id="cardMap" type="card"> <!--把结果集中cid这一列赋值给id属性--> <id column="cid" property="id"></id> <!--把结果集中cnumber这一列的值赋值给number属性--> <result column="cnumber" property="number"></result> <!--给person属性赋值--> <association property="person" javaType="person"> <!--把结果集中的pid这一列的值赋值给id属性--> <id column="pid" property="id"></id> <!--把结果集中的pname这一列的值赋值给name属性--> <result column="pname" property="name"></result> <!--把结果集中的page这一列的值赋值给age属性--> <result column="page" property="age"></result> </association> </resultMap> <select id="findAll" resultMap="cardMap"> SELECT c.id 'cid', c.number 'cnumber', p.id 'pid', p.name 'pname', p.age 'page' FROM card c LEFT JOIN person p ON p.id = c.pid </select> </mapper>
第五步:主配置导入映射文件
在mybatis-config.xml中的mappers标签中引入CardMapper.xml
<mappers> <mapper resource="CardMapper.xml"></mapper> </mappers>
第六步:编写测试方法
@Test public void testFindAll()throws Exception{ /*1.读取配置文件并创建SqlSessionFactory*/ InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); /*2.获取sqlSession[这是mybatis的重要API, 使用它可以操作数据库crud*/ SqlSession sqlSession = sqlSessionFactory.openSession(); /*3.由Mybatis框架创建CardDao的实现类对象,我们称为代理对象*/ CardDao cardDao = sqlSession.getMapper(CardDao.class); /*4.查询所有身份证*/ List<Card> cards = cardDao.findAll(); /*5.释放资源*/ sqlSession.close(); //测试查询结果 System.out.println(cards); }
1.1.4 小结
一对一查询,使用resultMap+association标签
1.2 一对多查询
1.2.1 表关系
一对多关系中,表关系由多的一方维护,以班级和学生为例,一个班级可以有多个学生,学生表应该维护表关系。
1.2.2 需求
查询所有班级信息,并且要将班级对应的学生信息也同时查询出来
1.2.3 实现步骤
第一步:建表
DROP TABLE IF EXISTS `classes`; CREATE TABLE `classes` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(20) DEFAULT NULL COMMENT '班级名称', PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='班级表'; INSERT INTO `classes`(`id`,`name`) VALUES (1,'一班'),(2,'二班'); DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(24) NOT NULL, `age` INT(11) NOT NULL, `cid` INT(11) NOT NULL COMMENT '所属班级', PRIMARY KEY (`id`), KEY `cid` (`cid`) ) ENGINE=INNODB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8; INSERT INTO `student`(`id`,`name`,`age`,`cid`) VALUES (8,'王力宏',23,1),(9,'张韶涵',22,1),(10,'张晋',24,1),(11,'罗晋',25,1),(12,'唐僧',12,2),(13,'孙悟空',22,2),(14,'猪八戒',21,2);
第二步:创建实体类
Student学生类
package cn.oldlu.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Student { private Integer id; private String name; private Integer age; }
Classes班级类,因为需求是查询班级,以及对应的学生,所以应该是班级类中定义List表示一堆学生
package cn.oldlu.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor public class Classes { private Integer id; private String name; private List<Student> students; }
第三步:创建Dao接口
package cn.oldlu.dao; import cn.oldlu.domain.Classes; import java.util.List; public interface ClassesDao { List<Classes> findAll(); }
第四步:创建映射文件
resultMap的分析与编写
在src或者resources目录下创建ClassesMapper.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="cn.oldlu.dao.ClassesDao"> <resultMap id="classesMap" type="classes"> <id column="cid" property="id"></id> <result column="cname" property="name"></result> <collection property="students" ofType="student"> <id column="sid" property="id"></id> <result column="sname" property="name"></result> <result column="sage" property="age"></result> </collection> </resultMap> <select id="findAll" resultMap="classesMap"> SELECT c.id 'cid', c.name 'cname', s.id 'sid', s.name 'sname', s.age 'sage' FROM classes c LEFT JOIN student s ON s.`cid` = c.`id` </select> </mapper>
第五步:主配置导入映射文件
在mybatis-config.xml中的mappers标签中引入ClassesMapper.xml
<mappers> <mapper resource="ClassesMapper.xml"></mapper> </mappers>
第六步:编写测试方法
@Test public void testFindAll()throws Exception{ /*1.读取配置文件并创建SqlSessionFactory*/ InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); /*2.获取sqlSession[这是mybatis的重要API, 使用它可以操作数据库crud*/ SqlSession sqlSession = sqlSessionFactory.openSession(); /*3.由Mybatis框架创建UserDao的实现类对象,我们称为代理对象*/ ClassesDao classesDao = sqlSession.getMapper(ClassesDao.class); /*4.查询所有班级*/ List<Classes> classes = classesDao.findAll(); /*5.释放资源*/ sqlSession.close(); //测试结果 System.out.println(classes); }
1.2.4 小结
一对多查询,使用resultMap+collection标签
总结:javatype和ofType 都是用来指明对象类型, 区别在于使用的场合不一样, javatype是在pojo属性类型, ofType指定是当对象需要Collection进行list集合映射对象的时候使用 ofType,也就是一对多映射的时候使用
1.3 多对多关系
1.3.1 表关系
多对多关系中表关系由中间表维护,以学生和课程为例,一个学生对应多们课程,一个课程同时对应多个学生
1.3.2 需求
查询所有的学生,并且要将学生对应的课程也查询出来
1.3.3 实现步骤
第一步: 建表
DROP TABLE IF EXISTS `classes`; CREATE TABLE `classes` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(20) DEFAULT NULL COMMENT '班级名称', PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='班级表'; INSERT INTO `classes`(`id`,`name`) VALUES (1,'一班'),(2,'二班'); DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(24) NOT NULL, `age` INT(11) NOT NULL, `cid` INT(11) NOT NULL COMMENT '所属班级', PRIMARY KEY (`id`), KEY `cid` (`cid`) ) ENGINE=INNODB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8; INSERT INTO `student`(`id`,`name`,`age`,`cid`) VALUES (8,'王力宏',23,1),(9,'张韶涵',22,1),(10,'张晋',24,1),(11,'罗晋',25,1),(12,'唐僧',12,2),(13,'孙悟空',22,2),(14,'猪八戒',21,2); DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(30) NOT NULL COMMENT '课程名', PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='课程表'; INSERT INTO `course`(`id`,`name`) VALUES (1,'语文'),(2,'数学'); DROP TABLE IF EXISTS `stu_cr`; CREATE TABLE `stu_cr` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `sid` INT(11) NOT NULL, `cid` INT(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; INSERT INTO `stu_cr`(`id`,`sid`,`cid`) VALUES (1,8,1),(2,8,2),(3,9,1),(4,10,2),(5,13,2),(6,13,1),(7,14,1),(8,11,2),(9,12,1),(10,12,2);
第二步:创建实体类
Course 课程类
package cn.oldlu.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Course { /**课程ID*/ private Integer id; /**课程名*/ private String name; }
Student 学生类,学生类之前已经定义过了,只需要添加新的course属性即可。因为需求是查询学生信息,以及对应的课程,所以应该在学生类中定义List,表示一堆课程
package cn.oldlu.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor public class Student { private Integer id; private String name; private Integer age; private List<Course> courses; }
第三步:创建Dao接口
package cn.oldlu.dao; import cn.oldlu.domain.Student; import java.util.List; public interface StudentDao { List<Student> findAll(); }
第四步:创建映射文件
resultMap的分析与编写
在src或resources目录下创建StudentMapper.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"> <!--namespace的值是UserDao的类全名--> <mapper namespace="cn.oldlu.dao.StudentDao"> <resultMap id="studentMap" type="student"> <!--把结果集中sid这一列赋值给id属性--> <id column="sid" property="id"></id> <!--把结果集中sname这一列的值赋值给name属性--> <result column="sname" property="name"></result> <!--把结果集中sage这一列的值赋值给age属性--> <result column="sage" property="age"></result> <!--给courses属性赋值--> <collection property="courses" ofType="course"> <!--把结果集中的cid这一列的值赋值给id属性--> <id column="cid" property="id"></id> <!--把结果集中的cname这一列的值赋值给name属性--> <result column="cname" property="name"></result> </collection> </resultMap> <select id="findAll" resultMap="studentMap"> SELECT s.id 'sid', s.name 'sname', s.age 'sage', c.id 'cid', c.name 'cname' FROM student s LEFT JOIN stu_cr sc ON s.id = sc.`sid` LEFT JOIN course c ON c.`id` = sc.`cid` </select> </mapper>
第五步:主配置导入映射文件
在mybatis-config.xml中的mappers标签中引入StudentMapper.xml
<mappers> <mapper resource="StudentMapper.xml"></mapper> </mappers>
第六步:编写测试方法
@Test public void testFindAll()throws Exception{ /*1.读取配置文件并创建SqlSessionFactory*/ InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); /*2.获取sqlSession[这是mybatis的重要API, 使用它可以操作数据库crud*/ SqlSession sqlSession = sqlSessionFactory.openSession(); /*3.由Mybatis框架创建UserDao的实现类对象,我们称为代理对象*/ StudentDao studentDao = sqlSession.getMapper(StudentDao.class); /*4.查询所有学生*/ List<Student> students = studentDao.findAll(); /*5.释放资源*/ sqlSession.close(); //测试结果 System.out.println(students); }
1.3.5 小结
多对多查询,使用resultMap+collection标签
1.4 多表查询总结
什么情况使用resultMap标签
情况1:如果查询的结果集的列名和实体类的属性名不匹配,就需要使用resultMap建立匹配规则
情况2:如果涉及到多表查询也需要使用resultMap标签,一对一查询用resultMap+association,一对多和多对多 resultMap+collection