Mybatis框架最通俗常用查询
一、模糊查询
1.创建对象
Student类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
private int id; //学生id
private String name; //学生姓名
//需要关联的一个老师
private Teacher teacher;
}
Teacher类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher implements Serializable {
private int id; // 老师id
private String name; // 老师姓名
//一个老师拥有多个学生
private List<Student> students;
}
2.编写接口
StudentMapper接口
public interface StudentMapper {
//根据姓名模糊查询 (这个才是这部分的要点,下面的是一些基础方法)
List<Student> getStudentsByName(@Param("name") String name);
/*
//获取所有学生信息
List<Student> getAllStudents();
//根据id查询学生信息
Student getStudentById(@Param("id") Integer id);
//增加一个学生
int addStudent(Student student);
//更新一个学生信息
int updateStudent(Student student);
//根据id删除一个学生信息
int deleteStudent(@Param("id") Integer id);
*/
}
TeacherMapper接口
public interface TeacherMapper {
//获取所有老师信息
List<Teacher> getAllTeacher();
//根据id查询老师信息
Teacher getTeacherById(@Param("id") Integer id);
//增加一个老师信息
int addTeacher(Teacher Teacher);
//更新一个老师信息
int updateTeacher(Teacher Teacher);
//根据id删除一个老师信息
int deleteTeacher(@Param("id") Integer id);
}
3.配置对应XML文件
只用配置Student类的接口映射文件即可
<?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.vinjcent.dao.StudentMapper">
<!-- 普通模糊查询 -->
<select id="getStudentsByName" parameterType="String" resultType="Student">
select * from student where name like #{name}
</select>
</mapper>
4.测试
测试一
@Test
public void testgetStudentsByName(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
//这里需要传递类型为String的参数
List<Student> students = studentMapper.getStudentsByName("Totoro");
//输出查询结果
students.forEach(System.out::println);
sqlSession.close();
}
结果
测试二
在对应XML文件中修改SQL语句
<!-- 使用%查询 -->
<select id="getStudentsByName" parameterType="String" resultType="Student">
select * from student where name like '%'#{name}'%'
</select>
结果
测试三(推荐)
同样在对应XML中修改,使用MySQL中的concat()
函数
<!-- 使用MySQL中的concat()函数 -->
<select id="getStudentsByName" parameterType="String" resultType="Student">
select * from student where name like concat('%',#{name},'%')
</select>
结果
二、联表查询
1. 多对一处理(多个Student对象,对应一个Teacher对象)
可以从上面看到,每次查询出来的结果Student类中的teacher属性都为null,这里我们通过对应接口的XML文件中的标签association来查询
1)编写StudentMapper接口
将上面的StudentMapper注释打开即可
2)在XML文件中映射接口方法
当在 ResultMap 中决定使用哪种类型处理器时,此时 Java 类型是已知的(从结果类型中获得),但是 JDBC 类型是未知的。 因此 Mybatis 使用 javaType=[Java 类型], jdbcType=null 的组合来选择一个类型处理器
【注意】这里的 select 语句中的结果必须指定 resultMap 而不是 resultType
<!--
id(resultMap中):当前文件中resultMap的唯一标识
type:我们的javaType
result:返回的属性字段 //property ===> java实体类中的属性字段
//column ===> 数据库查询对应的字段
复杂的属性,我们需要单独处理
对象: association
javaType: 在java中的类型
select: 引用当前文件中,标签为select的唯一标识
-->
<resultMap id="StudentAndTeacher" type="Student">
<id property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacherById"/>
</resultMap>
<select id="getTeacherById" resultType="Teacher">
select * from teacher where id = #{id}
</select>
<!-- resultMap结果集映射 -->
<select id="getAllStudents" resultMap="StudentAndTeacher">
select * from student
</select>
3)测试
这里我们使用查询全部学生的方法getAllStudents()
@Test
public void testgetAllStudents(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
//
List<Student> students = studentMapper.getAllStudents();
//输出查询结果
students.forEach(System.out::println);
sqlSession.close();
}
结果
2. 一对多处理(一个Teacher对象,对应多个Student对象)
看完刚刚的多对一,可以知道Teacher类中有一个属性为List的泛型集合,当我们想查询完整时,又如何去做呢?
1)编写TeacherMapper接口
上面已经写过了,就不重复写了
2)在XML文件中映射接口方法
千万要注意这里的子查询!!!
<!--
这里并没有错,在我们结果集映射时,传递的参数Param("id")是老师的id
查出结果后,我们再用老师的id作为collection标签中的column属性的值
而这里的#{id}也就是老师的id,student表中有tid(老师id)字段
-->
<select id="getStudentByTeacherId" resultType="Student">
select * from student where tid = #{id}
</select>
完整XML映射文件
<!--
集合:collection
javaType:指定属性的类型
集合中的泛型信息,我们使用ofType
collection标签中的column是数据库对应表的字段,因为是根据teacher表查询的,所以这里column对应的是teacher表中的id
-->
<resultMap id="TeacherAndStudents" type="Teacher">
<result property="id" column="id"/>
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentsByTeacherId" column="id">
</collection>
</resultMap>
<select id="getStudentsByTeacherId" resultType="Student">
select * from student where tid = #{id}
</select>
<select id="getTeacherById" resultMap="TeacherAndStudents">
select * from teacher where id = #{id}
</select>
3)测试
@Test
public void testgetTeacherById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = teacherMapper.getTeacherById(1);
//输出查询结果
System.out.println(teacher);
sqlSession.close();
}
结果
3. 注意点
- 保证SQL的可读性,尽量保证通俗易懂
- 注意一对多和多对一中,属性名和字段名的问题
- 如果问题不好排查错误,可以使用日志,建议使用log4j(在我的《Mybatis学习笔记(三)》)有提到
三、结果嵌套和查询嵌套
为了让大家更加能够区分结果嵌套
和查询嵌套
的区别,我们重新建几个类演示一下
数据库设计
(1)三张表(Student、Subject、Sheet)
# 学生表
CREATE TABLE `student` (
`id` INT(4) NOT NULL COMMENT '学生ID',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`age` INT(3) NOT NULL DEFAULT '0' COMMENT '年龄',
`sex` VARCHAR(2) NOT NULL DEFAULT '未知' COMMENT '性别',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
# 课程表
CREATE TABLE `subject` (
`id` INT(4) NOT NULL COMMENT '课程ID',
`name` VARCHAR(30) NOT NULL COMMENT '课程名',
`average` DOUBLE DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
# 成绩表
CREATE TABLE `sheet` (
`studentId` INT(4) NOT NULL COMMENT '学生ID',
`subjectId` INT(4) NOT NULL COMMENT '课程ID',
`score` DOUBLE DEFAULT NULL COMMENT '分数',
KEY `studentId` (`studentId`),
KEY `subjectId` (`subjectId`),
CONSTRAINT `sheet_ibfk_1` FOREIGN KEY (`studentId`) REFERENCES `student` (`id`),
CONSTRAINT `sheet_ibfk_2` FOREIGN KEY (`subjectId`) REFERENCES `subject` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
(2)对应实体类
//学生类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
/**
* 学生ID
*/
private Integer id;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 性别
*/
private String sex;
}
//课程类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Subject implements Serializable {
/**
* 课程ID
*/
private Integer id;
/**
* 课程名
*/
private String name;
/**
* 平均成绩
*/
private double average;
}
//成绩类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Sheet implements Serializable {
/**
* 学生ID
*/
private Student student;
/**
* 课程ID
*/
private Subject subject;
/**
* 分数
*/
private Double score;
}
(3)Mapper接口
这里我们只写成绩类的接口SheetMapper即可
public interface SheetMapper {
// 根据模糊 + 条件,查询学生的成绩 方式一:查询嵌套
List<Sheet> getStudentsByConditions1(Map<String,Object> map);
// 根据模糊 + 条件,查询学生的成绩 方式二:结果嵌套
List<Sheet> getStudentsByConditions2(Map<String,Object> map);
}
(4)对应XML文件
也是只用写一个SheetMapper.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.vinjcent.dao.SheetMapper">
<!--根据id查询学生-->
<select id="getStudentById" resultType="Student">
select * from student
where id = #{id}
</select>
<!--根据id查询课程-->
<select id="getSubjectById" resultType="Subject">
select * from subject
where id = #{id}
</select>
<resultMap id="Query_nesting" type="Sheet">
<association property="student" column="studentId" javaType="Student" select="getStudentById">
</association>
<association property="subject" column="subjectId" javaType="Subject" select="getSubjectById">
</association>
</resultMap>
<!--查询学生的成绩 方式一:查询嵌套-->
<select id="getStudentsByConditions1" resultMap="Query_nesting" parameterType="map">
select * from sheet
</select>
<!--=====================================================================-->
<!--查询学生的成绩 方式二:结果嵌套-->
<resultMap id="Result_nesting" type="Sheet">
<result property="student.id" column="stuId"/>
<result property="student.name" column="stuName"/>
<result property="subject.name" column="subName"/>
<result property="score" column="score"/>
</resultMap>
<select id="getStudentsByConditions2" resultMap="Result_nesting" parameterType="map">
select
stu.id stuId,
stu.name stuName,
sub.name subName,
score
from student stu
right join sheet s
on stu.id = s.studentId
inner join subject sub
on s.subjectId = sub.id
</select>
</mapper>
1. 结果嵌套处理
在XML文件中,我们上半部分
就是结果嵌套处理的代码,因为在设计数据库时,成绩表Sheet就三个字段
而在成绩表实体类Sheet中,它有两个属性是对象,所以要进行两次子查询
原理就是在数据库中先查Sheet类,再根据数据库表Sheet的两个字段进行子查询
2. 查询嵌套处理
当然,对应的XML下半段
就是我们的查询嵌套,我们先来看看这段sql语句查询了什么
select
stu.id stuId,
stu.name stuName,
sub.name subName,
score
from student stu
right join sheet s
on stu.id = s.studentId
inner join subject sub
on s.subjectId = sub.id
结果
这里的查询是将3个表中指定字段的内容挑选出来,也就是我们想要得到的数据,由于挑选出来的数据并不都在一个表中,我们要对查询出来的结果进行映射到Sheet类中属性为对象中的属性中(有点拗口),然后才结束查询,我们来看看具体过程
结论
从这两种方式的查询来看,SQL语句代码量结果嵌套
可能会更多点,但是,但也很明确地一步一步进行查询,从外到里。而查询嵌套
更注重于对SQL语句掌握的基础,直接进行数据库的联表查询,查询我们想要的指定内容