java学习之 MyBatis-day02
Mapper组件
- 使用Mapper组件
- 类似DAO,在接口中定义 CRUD 等操作方法。Mapper 组件 = Mapper 接口 + Mapper XML 文件。
- 接口的命名为实体名 + Mapper,一般和其对应 XML 文件放一起
- XML 命名空间及 namespace="用其对应接口的全限定名"
- Mapper 接口的方法名要和 Mapper XML 文件元素 一致
- 方法的返回类型对应 SQL 元素中定义的 resultType / resultMap 类型;
- 方法的参数类型对应 SQL 元素中定义的 paramterType 类型(一般不写)。
Mapper 接口的原理
接口是规范,实质做的实现还是要由实现类对象来做,而这个实现类不需要我们写,实现类对象也不由我们创建,这些都 MyBatis 使用动态代理帮我们做了 提供 Mapper 接口对应 Mapper XML 文件,获取实现类对象的时候传入 Mapper 接口字节码
@Param 注解
@Param 注解是 MyBatis 中的一个注解,用于指定方法参数的名称。它的主要作用是解决方法参数名称在编译期被丢失的问题,并且可以让你在 XML 映射文件中更加清晰地引用方法参数。
指定方法参数的名称: Java 中,方法参数的名称在编译后会被丢弃,而只保留参数的类型。这意味着在 XML 映射文件中,你无法通过参数名称来引用方法参数。使用 @Param 注解可以为方法参数指定一个名称,这个名称将用于 XML 映射文件中
▼java复制代码public List<User> findUsers(@Param("name") String name, @Param("age") int age);
当传递一个 List 对象或数组对象参数给 MyBatis 时,MyBatis 会自动把它包装到一个 Map 中,此时:List 对象会以 list 作为 key,数组对象会以 array 作为 key,也可以使用注解 @Param 设置 key 名。
MyBatis 的 # 和 $
| 特性 | # 占位符 | $ 占位符 |
|---|---|---|
| 参数替换方式 | 安全替换(预编译) | 文本替换(不安全) |
| 替换参数 | 使用?替代参数 | 直接替换参数值 |
| 替换后的值 | 将参数值作为预编译参数 | 将参数值直接嵌入 SQL 文本 |
| 防止 SQL 注入攻击 | 是 | 否 |
| 支持表名和列名替换 | 否 | 是 |
| 字符串拼接 | 不需要手动添加单引号 | 需要手动添加单引号 |
| 适用于参数的数据类型 | 通常适用于所有数据类型 | 主要用于处理字符串和 SQL 片段 |
| 推荐使用 | 推荐使用 # | 慎用 $,容易受到 SQL 注入攻击的风险 |
| 示例 | WHERE id = #{id} | WHERE id = ${id} |
动态SQL
利用动态 SQL 这一特性可以彻底摆脱根据不同条件拼接 SQL 语句的痛苦
<where>标签
<where> 标签用于在 SQL 查询中包装多个条件,通常是多个条件之间使用 AND 连接。这个标签会自动处理前置的 WHERE 关键字,并且只在有条件存在时添加 WHERE 关键字。
-if 标签
<if> 标签用于根据条件包含或排除 SQL 查询的一部分。它允许你在运行时检查一个条件,如果条件为真,则包含<if>标签内的内容,否则将忽略它。
例如:
▼xml复制代码<select id="selectUsers" parameterType="User" resultType="User"> SELECT * FROM users <where> <if test="name != null"> AND name = #{name} </if> <if test="age != null"> AND age = #{age} </if> </where> </select>
示例中,< where > 标签包装了两个 < if > 标签,每个 < if > 标签用于检查一个条件是否满足。如果 name 和/或 age 存在,则它们会被包含在 WHERE 子句中,否则 WHERE 子句将为空。
多表查询
关系应用
生活中数据很多是存在关系,且存储的数据也能表示出来这种关系
- 保存:页面的数据 ---> 使用 Java 对象封装 ---> 通过 MyBatis ---> 数据库表的数据
- 查询:数据库表的数据 ---> 通过 MyBatis ---> 封装成 Java 对象 ---> 页面展示数据
对象关系分类
- 泛化关系
- 实现关系
- 依赖关系
- 关联关系
- 聚合关系
- 组合关系
关联关系
A 对象依赖 B 对象,并且把 B 作为 A 的一个成员变量,则 A 和 B 存在关联关系。在 UML 中依赖通常使用实线箭头表示。
分类
- 按照导航性分
若通过 A 对象中的某一个属性可以访问到 B 对象,则说 A 可以导航到 B。
- 单向:只能从 A 通过属性导航到 B,B 不能导航到 A。
- 双向:A 可以通过属性导航到 B,B 也可以通过属性导航到 A。
- 按照多重性分
- 一对一
- 一对多
- 多对一
- 多对多。
判断关联关系的分类
- 判断都是从对象的实例上面来看的;
- 判断关系需要根据对象的属性;
- 判断关系必须确定具体需求。
单向多对一之额外 SQL 查询
单向多对一关系通常用于描述一个实体(多的一端)关联到另一个实体(一的一端)。在MyBatis中,您可以使用额外的SQL查询来检索与多对一关系相关联的数据。
以下是单向多对一关系中使用额外SQL查询的示例:
假设我们有两个实体类:Student 和 Cource ,假设一个学生对应一个课程,即多个学生可能有同一课程。
实体类示例:
▼java复制代码//课程类 @AllArgsConstructor @Getter @Setter @ToString @NoArgsConstructor public class Course { private Long id; private String Name; } //学生类 @Getter @Setter @AllArgsConstructor @NoArgsConstructor @ToString public class Student { private Long id; private String Name; private Integer Age; private Course course; }
映射文件示例:
▼xml复制代码<!--课程查询 --> <resultMap id="CourseResultMap" type="Course"> <id property="id" column="ID"/> <result property="Name" column="CouName"/> </resultMap> <select id="selectById" resultMap="CourseResultMap"> select * from course where id=#{id} </select> <!--学生查询 --> <!-- 通过查询过程中的id查询 对应的课程信息 --> <resultMap id="BaseMap" type="Student"> <id property="id" column="id"/> <result property="name" column="StuName"/> <result property="age" column="StuAge"/> <association property="course" select="mybatis.xyz.bycor.mapper.CourseMapper.selectById" column="Cid"> </association> </resultMap> <!-- 查询单个学生的信息 (包括课程信息) --> <select id="selectById" resultMap="BaseMap"> SELECT * FROM student where id=#{id} </select> <!-- 查询所有学生的信息 (包括课程信息) --> <select id="selectAll" resultMap="BaseMap"> SELECT * FROM student </select> <!-- 查询所有学生的信息 (包括课程信息) 方式 2--> <resultMap id="BaseMap2" type="Student" > <id column="id" property="id"/> <result column="StuName" property="name"/> <result column="StuAge" property="age"/> <result column="CouName" property="course.name"/> <result column="Cid" property="course.id"/> </resultMap> <select id="selectAll2" resultMap="BaseMap2"> select s.id,s.StuName,s.StuAge,c.CouName,c.id Cid from student s join course c on c.id = s.Cid </select> <!-- 查询所有学生的信息 (包括课程信息) 方式 3--> <resultMap id="BaseMap3" type="Student"> <id column="id" property="id"/> <result column="StuName" property="name"/> <result column="StuAge" property="age"/> <association property="course" columnPrefix="c_" javaType="Course"> <result column="id" property="id"/> <result column="CouName" property="name"/> </association> </resultMap> <select id="selectAll3" resultMap="BaseMap3"> select s.id,s.StuName,s.StuAge,c.CouName c_CouName,c.id c_id from student s join course c on c.id = s.Cid </select>
Java Mapper代码示例:
▼java复制代码public interface CourseMapper { // 增删 改 查 void delete(Long id); void update(Course course); List<Course> selectAll(); void insert(Course course); Course selectById(Long id); } public interface StudentMapper { // 增删 改 查 void insert(Student student); void delete(Long id); void update(Student student); Student selectById(Long id); List<Student> selectAll(); List<Student> selectAll2(); List<Student> selectAll3(); }
Java Test代码示例:
▼java复制代码@Test public void testMany2OneSelect() { // 查询某个的学生信息包括对应的课程信息 SqlSession sqlSession = MybatisUtil.getSqlSession(); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); Student student = mapper.selectById(2L); sqlSession.close(); System.out.println(student); } @Test public void testMany2OneSelectAll() { // 查询所有学生信息包括对应的课程信息 SqlSession sqlSession = MybatisUtil.getSqlSession(); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); List<Student> students = mapper.selectAll(); sqlSession.close(); students.forEach(System.out::println); }
在上述示例中,我们定义了一个名为 selectAllXXX 的查询操作,它用于获取所有学生的信息,包括他们所选的课程信息。这个查询使用了一个自定义的结果映射 BaseMap3,将学生的属性和相关的课程信息进行关联。
下面是这个查询的要点总结:
查询操作:selectAll3,用于获取所有学生的信息以及他们所选的课程信息。
结果映射:BaseMap3,自定义结果映射,用于将查询结果映射到 Student 类型的对象上。
查询语句:SQL 查询语句联接了 student 表和 course 表,通过学生表的外键关联了相关的课程信息。
结果映射配置:在结果映射中,我们定义了学生属性的映射,以及关联的课程属性的映射。这样,查询结果将自动映射到 Student 对象的属性中,包括学生的基本信息和所选课程的信息。
通过这种方式,我们可以一次性获取学生和他们所选课程的信息,无需手动处理查询结果集的关联,提高了代码的可读性和查询效率。这是 MyBatis 中处理多表关联查询的一种常见方法。

