MyBatis 快速入门

什么是 MyBatis?

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

和其它持久化层技术对比 

JDBC

优点:

  • 灵活性:可以直接使用原生 SQL,对 SQL 有完全的控制。
  • 性能:由于没有额外的抽象层,通常性能较高。

缺点:

  • 耦合度高:SQL 语句硬编码在 Java 代码中,代码耦合度高,不易维护。
  • 冗长:需要编写大量重复的样板代码(如连接、关闭资源等),开发效率低。
  • 维护难:SQL 语句的变动需要频繁修改代码,影响维护性。

Hibernate 和 JPA

优点:

  • 开发效率高:提供了对象关系映射(ORM)功能,减少了大量的 JDBC 代码,开发效率高。
  • 自动化:通过注解或 XML 配置实现数据表和 Java 对象的映射,简化开发。
  • 支持缓存:内置一级缓存和二级缓存,能提高性能。
  • 跨数据库支持:可以通过配置适配不同的数据库。

缺点:

  • 复杂 SQL:对于复杂的查询,可能需要使用 HQL 或原生 SQL,有时绕过 ORM 框架进行优化。
  • 性能问题:反射和动态代理等技术可能导致性能下降,尤其是在大规模数据操作时。
  • 映射难题:大量字段或复杂的 POJO 映射可能导致配置困难,映射过程中的错误可能难以排查。

MyBatis

优点:

  • 轻量级:比 Hibernate 和 JPA 更轻量,不涉及 ORM 复杂度,直接映射 SQL 到 Java 对象。
  • 灵活性:允许编写原生 SQL,使得复杂的查询和优化变得更容易。
  • 分离关注点:SQL 和 Java 代码分开,保持代码清晰,Java 代码专注于业务逻辑,SQL 专注于数据操作。

缺点:

  • 开发效率:需要手动编写 SQL 和映射语句,开发效率可能稍逊于 Hibernate 和 JPA。
  • 维护性:虽然 SQL 和 Java 代码分离,但大量 SQL 语句的编写和维护仍然需要额外的工作。

总结

  • JDBC 适合对性能有严格要求的应用,或者需要高度自定义 SQL 的场景,但缺乏框架支持,开发维护难度较大。
  • Hibernate 和 JPA 更适合需要快速开发且数据库操作较为标准化的场景,适合使用 ORM 的优势,但可能在处理复杂查询时性能和灵活性受限。
  • MyBatis 提供了 SQL 和业务逻辑的清晰分离,适合需要复杂 SQL 查询并希望有较高性能控制的场景,同时开发效率较 JDBC 更高,但不及 Hibernate 和 JPA。

安装 

要使用 MyBatis, 只需将 mybatis-x.x.x.jar 文件置于类路径(classpath)中即可。

如果使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml 文件中:

<dependencies>
        <!-- 引入Spring Boot Web启动器,用于创建Web应用程序 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 引入Spring Boot测试启动器,用于编写和运行单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 引入MyBatis Spring Boot启动器,简化MyBatis与Spring Boot的集成 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>
        <!-- 引入MySQL数据库驱动,用于连接MySQL数据库 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version> <!-- 使用对应的数据库驱动 -->
        </dependency>
        <!-- 引入Lombok库,简化Java代码,自动生成getter、setter等 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

配置数据库连接字符串和MyBatis

如果配置文件是application.properties,代码如下:

# 数据库配置
# 数据库连接URL
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_test
# 数据库用户名
spring.datasource.username=root
# 数据库密码
spring.datasource.password=123456
# 数据库驱动类名
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# MyBatis配置
# 指定MyBatis的日志实现方式
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 开启下划线到驼峰命名的转换支持
mybatis.configuration.map-underscore-to-camel-case=true
# 指定Mapper文件的位置
mybatis.mapper-locations=classpath*:mappers/*.xml

如果配置文件是application.yml,代码如下:

# 配置Spring框架的数据源信息
spring:
  datasource:
    # 数据库连接URL
    url: jdbc:mysql://localhost:3306/mybatis_test
    # 数据库用户名
    username: root
    # 数据库密码
    password: 123456
    # 数据库驱动类名称
    driver-class-name: com.mysql.cj.jdbc.Driver

# 配置MyBatis框架的相关属性
mybatis:
  configuration:
    # 日志实现类,这里配置的是输出到控制台的日志实现
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    # 是否开启下划线到驼峰命名的转换,设为true后,MyBatis会自动将列名从下划线命名转换为驼峰命名
    map-underscore-to-camel-case: true
  # 指定Mapper文件的位置,这里使用通配符匹配所有Mapper文件
  mapper-locations: classpath:mappers/*.xml

MySQL

CREATE DATABASE IF NOT EXISTS mybatis_test;
USE mybatis_test;
-- 创建教师表
CREATE TABLE IF NOT EXISTS teacher (
    id INT AUTO_INCREMENT PRIMARY KEY, -- 教师的唯一标识符
    name VARCHAR(255) NOT NULL, -- 教师姓名
    course_name VARCHAR(255), -- 教师教授的课程名称
    is_employed TINYINT(1) NOT NULL, -- 是否在职 (1: 在职, 0: 不在职)
    title TINYINT(1) NOT NULL, -- 教师职称 (0: 初级, 1: 高级)
    email VARCHAR(255), -- 教师邮箱
    phone_number VARCHAR(20) -- 教师电话
);

-- 创建课程表
CREATE TABLE IF NOT EXISTS course (
    id INT AUTO_INCREMENT PRIMARY KEY, -- 课程的唯一标识符
    course_name VARCHAR(255) NOT NULL, -- 课程名称
    teacher_id INT, -- 负责该课程的教师ID
    class_name VARCHAR(255), -- 班级名称
    schedule VARCHAR(255), -- 上课时间安排
    location VARCHAR(255), -- 上课地点
    FOREIGN KEY (teacher_id) REFERENCES teacher(id) -- 外键,引用教师表中的id
);

-- 创建学生表
CREATE TABLE IF NOT EXISTS student (
    id INT AUTO_INCREMENT PRIMARY KEY, -- 学生的唯一标识符
    name VARCHAR(255) NOT NULL, -- 学生姓名
    course_name VARCHAR(255), -- 学生所选课程名称
    teacher_id INT, -- 该课程的教师ID
    class_name VARCHAR(255), -- 班级名称
    enrollment_date DATE, -- 入学日期
    address VARCHAR(255), -- 学生住址
    FOREIGN KEY (teacher_id) REFERENCES teacher(id) -- 外键,引用教师表中的id
);

-- 插入教师数据
INSERT INTO teacher (name, course_name, is_employed, title, email, phone_number) VALUES
('张三', '数学', 1, 0, 'zhangsan@example.com', '1234567890'),
('李四', '语文', 1, 1, 'lisi@example.com', '0987654321'),
('王五', '英语', 0, 0, 'wangwu@example.com', '1122334455');

-- 插入课程数据
INSERT INTO course (course_name, teacher_id, class_name, schedule, location) VALUES
('数学', 1, '一班', '周一 9:00-11:00', '教室101'),
('语文', 2, '二班', '周三 13:00-15:00', '教室102'),
('英语', 3, '三班', '周五 15:00-17:00', '教室103');

-- 插入学生数据
INSERT INTO student (name, course_name, teacher_id, class_name, enrollment_date, address) VALUES
('小明', '数学', 1, '一班', '2024-09-01', '北京市朝阳区'),
('小红', '语文', 2, '二班', '2024-09-01', '上海市浦东新区'),
('小李', '英语', 3, '三班', '2024-09-01', '深圳市南山区'),
('小王', '数学', 1, '一班', '2024-09-01', '广州市番禺区'),
('小赵', '语文', 2, '二班', '2024-09-01', '北京市海淀区'),
('小钱', '英语', 3, '三班', '2024-09-01', '上海市徐汇区'),
('小刚', '英语', 3, '三班', '2024-09-01', '广州市天河区');

MyBatis XML基础操作

查询操作(SELECT)

当查询2024-09-01入学学生的学生的唯一标识符、学生姓名、学生所选课程名称、该课程的教师、班级名称、学生住址的时候

<?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,负责数据库中学生信息的操作 -->
<mapper namespace="com.example.mybatisdemo.mapper.StudentMapper">

    <!-- 根据入学日期查询学生信息 -->
    <!-- 说明:此SQL语句用于根据学生的入学日期获取学生的基本信息、课程名称、教师名称、班级名称和地址 -->
    <select id="getStudentsByEnrollmentDate" resultType="com.example.mybatisdemo.model.StudentInfo">
        SELECT s.id AS studentId, s.name AS studentName, s.course_name AS courseName, t.name AS teacherName, s.class_name AS className, s.address AS address
        FROM student s
                 JOIN teacher t ON s.teacher_id = t.id
        WHERE s.enrollment_date = #{date}
    </select>

</mapper>
package com.example.mybatisdemo.model;

import lombok.Data;

/**
 * 学生信息模型类
 * 用于描述学生的基本信息,包括学生ID、姓名、课程名称、教师名称、班级名称和地址
 */
@Data
public class StudentInfo {

    // 学生ID,用于唯一标识一个学生
    private Integer studentId;

    // 学生姓名
    private String studentName;

    // 课程名称,表示学生所选的课程
    private String courseName;

    // 教师名称,表示授课教师
    private String teacherName;

    // 班级名称,表示学生所在的班级
    private String className;

    // 学生的地址信息
    private String address;
}
package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.StudentInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 学生信息的持久层接口,负责与数据库进行交互
 */
@Repository
@Mapper
public interface StudentMapper {

    /**
     * 根据入学日期获取学生列表
     *
     * @param date 入学日期,用于数据库查询条件
     * @return 匹配入学日期的学生列表
     */
    List<StudentInfo> getStudentsByEnrollmentDate(@Param("date") String date);
}

package com.example.mybatisdemo.service;

import com.example.mybatisdemo.mapper.StudentMapper;
import com.example.mybatisdemo.model.StudentInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 学生服务类
 * 该类用于提供关于学生信息的服务,包括根据入学日期查询学生信息等
 */
@Service
public class StudentService {

    /**
     * 注入学生Mapper接口
     * 用于访问数据库中的学生信息
     */
    @Autowired
    private StudentMapper studentMapper;

    /**
     * 根据入学日期获取学生列表
     *
     * @param date 入学日期,格式为yyyy-MM-dd
     * @return 与给定入学日期对应的学生信息列表
     */
    public List<StudentInfo> getStudentsByEnrollmentDate(String date) {
        // 调用Mapper方法,根据入学日期查询学生信息列表
        return studentMapper.getStudentsByEnrollmentDate(date);
    }
}
package com.example.mybatisdemo.controller;

import com.example.mybatisdemo.model.StudentInfo;
import com.example.mybatisdemo.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * 学生控制器类,用于处理与学生相关的信息请求
 */
@RestController
@RequestMapping("/students")
public class StudentController {

    /**
     * 注入的学生服务,用于调用学生相关业务逻辑
     */
    @Autowired
    private StudentService studentService;

    /**
     * 根据入学日期获取学生列表
     *
     * @param date 入学日期,用于筛选学生的入学时间条件
     * @return 符合入学日期条件的学生列表
     */
    @GetMapping("/enrollment")
    public List<StudentInfo> getStudentsByEnrollmentDate(@RequestParam String date) {
        return studentService.getStudentsByEnrollmentDate(date);
    }
}

插入操作(INSERT)

当新老师入职时,在MySQL插入一条老师信息

TeacherMapper.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.example.demo.mapper.TeacherMapper">

    <!-- 定义插入老师信息的 SQL 语句 -->
    <insert id="insertTeacher" parameterType="com.example.demo.model.Teacher">
        INSERT INTO teacher (name, course_name, is_employed, title, email, phone_number)
        VALUES (#{name}, #{courseName}, #{isEmployed}, #{title}, #{email}, #{phoneNumber})
    </insert>

</mapper>

Java 代码

package com.example.demo.model;

import lombok.Data;

/**
 * Teacher类表示教师的信息
 * 该类使用了Lombok的@Data注解,自动生成getter、setter、toString、equals和hashCode方法
 */
@Data
public class Teacher {
    // 教师的ID,唯一标识
    private Integer id;

    // 教师的姓名
    private String name;

    // 教师所教授的课程名称
    private String courseName;

    // 标识教师是否受雇
    private Boolean isEmployed;

    // 标识教师是否有职称
    private Boolean title;

    // 教师的电子邮件地址
    private String email;

    // 教师的电话号码
    private String phoneNumber;
}
package com.example.demo.mapper;

import com.example.demo.model.Teacher;
import org.apache.ibatis.annotations.Mapper;

/**
 * TeacherMapper 接口定义了与 Teacher 实体相关的操作,专注于数据访问和操作。
 * 通过 @Mapper 注解,将其指定为 MyBatis 映射器接口。
 */
@Mapper
public interface TeacherMapper {
    /**
     * 将新的教师记录插入数据库。
     * 此方法使用传入的 Teacher 对象在数据库中执行插入操作,持久化教师的信息。
     *
     * @param teacher 包含待插入教师信息的 Teacher 对象
     */
    void insertTeacher(Teacher teacher);
}
package com.example.demo.service;

import com.example.demo.model.Teacher;
import com.example.demo.mapper.TeacherMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * TeacherService类用于处理教师相关的业务逻辑
 */
@Service
public class TeacherService {

    @Autowired
    private TeacherMapper teacherMapper;

    /**
     * 添加教师信息
     *
     * @param teacher 教师对象,包含要插入数据库的教师信息
     */
    public void addTeacher(Teacher teacher) {
        teacherMapper.insertTeacher(teacher);
    }
}
package com.example.demo.controller;

import com.example.demo.model.Teacher;
import com.example.demo.service.TeacherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * TeacherController类用于处理与老师相关的HTTP请求
 */
@RestController
@RequestMapping("/teachers")
public class TeacherController {

    /**
     * TeacherService实例,用于调用老师相关的业务逻辑
     */
    @Autowired
    private TeacherService teacherService;

    /**
     * 处理添加老师的请求
     *
     * @param teacher 要添加的老师对象,从请求体中获取
     * @return 添加成功后的提示信息
     */
    @PostMapping("/add")
    public String addTeacher(@RequestBody Teacher teacher) {
        teacherService.addTeacher(teacher);
        return "老师添加成功!";
    }
}

老师添加成功!

更新操作(UPDATE)

当新老师入职时,教师电话填写错了,得修改一下!

得在 TeacherMapper.xml 中添加一个新的 SQL 语句来更新教师的电话信息。

<?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.example.demo.mapper.TeacherMapper">

    <!-- 定义插入老师信息的 SQL 语句 -->
    <insert id="insertTeacher" parameterType="com.example.demo.model.Teacher">
        INSERT INTO teacher (name, course_name, is_employed, title, email, phone_number)
        VALUES (#{name}, #{courseName}, #{isEmployed}, #{title}, #{email}, #{phoneNumber})
    </insert>
    <!-- 定义更新教师电话的 SQL 语句 -->
    <update id="updateTeacherPhoneNumber" parameterType="com.example.demo.model.Teacher">
        UPDATE teacher
        SET phone_number = #{phoneNumber}
        WHERE name = #{name} AND email = #{email}
    </update>
</mapper>

package com.example.demo.mapper;

import com.example.demo.model.Teacher;
import org.apache.ibatis.annotations.Mapper;

/**
 * TeacherMapper 接口定义了与 Teacher 实体相关的操作,专注于数据访问和操作。
 * 通过 @Mapper 注解,将其指定为 MyBatis 映射器接口。
 */
@Mapper
public interface TeacherMapper {
    /**
     * 将新的教师记录插入数据库。
     * 此方法使用传入的 Teacher 对象在数据库中执行插入操作,持久化教师的信息。
     *
     * @param teacher 包含待插入教师信息的 Teacher 对象
     */
    void insertTeacher(Teacher teacher);

    /**
     * 更新教师的联系电话。
     * 通过此方法,可以根据 Teacher 对象中的信息更新数据库中教师的联系电话。
     *
     * @param teacher 包含待更新教师信息的 Teacher 对象
     */
    void updateTeacherPhoneNumber(Teacher teacher);
}
package com.example.demo.service;

import com.example.demo.model.Teacher;
import com.example.demo.mapper.TeacherMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * TeacherService类用于处理教师相关的业务逻辑
 */
@Service
public class TeacherService {

    @Autowired
    private TeacherMapper teacherMapper;

    /**
     * 添加教师信息
     *
     * @param teacher 教师对象,包含要插入数据库的教师信息
     */
    public void addTeacher(Teacher teacher) {
        teacherMapper.insertTeacher(teacher);
    }

    /**
     * 更新教师的电话号码
     *
     * @param teacher 教师对象,包含需要更新电话号码的教师信息
     */
    public void updateTeacherPhoneNumber(Teacher teacher) {
        teacherMapper.updateTeacherPhoneNumber(teacher);
    }
}
package com.example.demo.controller;

import com.example.demo.model.Teacher;
import com.example.demo.service.TeacherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * TeacherController类用于处理与老师相关的HTTP请求
 */
@RestController
@RequestMapping("/teachers")
public class TeacherController {

    /**
     * TeacherService实例,用于调用老师相关的业务逻辑
     */
    @Autowired
    private TeacherService teacherService;

    /**
     * 处理添加老师的请求
     *
     * @param teacher 要添加的老师对象,从请求体中获取
     * @return 添加成功后的提示信息
     */
    @PostMapping("/add")
    public String addTeacher(@RequestBody Teacher teacher) {
        teacherService.addTeacher(teacher);
        return "老师添加成功!";
    }

    /**
     * 处理更新老师电话号码的请求
     *
     * @param teacher 包含需要更新电话号码的老师对象,从请求体中获取
     * @return 更新成功后的提示信息
     */
    @PutMapping("/updatePhone")
    public String updateTeacherPhoneNumber(@RequestBody Teacher teacher) {
        teacherService.updateTeacherPhoneNumber(teacher);
        return "教师电话号码更新成功!";
    }
}

删除操作(DELETE)

当新老师入职后,发现学校太垃圾了,然后跑路了,这时MySQL得删除一下!

<?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.example.demo.mapper.TeacherMapper">

    <!-- 定义插入老师信息的 SQL 语句 -->
    <insert id="insertTeacher" parameterType="com.example.demo.model.Teacher">
        INSERT INTO teacher (name, course_name, is_employed, title, email, phone_number)
        VALUES (#{name}, #{courseName}, #{isEmployed}, #{title}, #{email}, #{phoneNumber})
    </insert>
    <!-- 定义更新教师电话的 SQL 语句 -->
    <update id="updateTeacherPhoneNumber" parameterType="com.example.demo.model.Teacher">
        UPDATE teacher
        SET phone_number = #{phoneNumber}
        WHERE name = #{name} AND email = #{email}
    </update>
    <!-- 定义删除老师信息的 SQL 语句 -->
    <delete id="deleteTeacher" parameterType="com.example.demo.model.Teacher">
        DELETE FROM teacher
        WHERE name = #{name} AND email = #{email}
    </delete>
</mapper>

package com.example.demo.mapper;

import com.example.demo.model.Teacher;
import org.apache.ibatis.annotations.Mapper;

/**
 * TeacherMapper 接口定义了与 Teacher 实体相关的操作,专注于数据访问和操作。
 * 通过 @Mapper 注解,将其指定为 MyBatis 映射器接口。
 */
@Mapper
public interface TeacherMapper {
    /**
     * 将新的教师记录插入数据库。
     * 此方法使用传入的 Teacher 对象在数据库中执行插入操作,持久化教师的信息。
     *
     * @param teacher 包含待插入教师信息的 Teacher 对象
     */
    void insertTeacher(Teacher teacher);

    /**
     * 更新教师的联系电话。
     * 通过此方法,可以根据 Teacher 对象中的信息更新数据库中教师的联系电话。
     *
     * @param teacher 包含待更新教师信息的 Teacher 对象
     */
    void updateTeacherPhoneNumber(Teacher teacher);

    /**
     * 删除教师记录。
     * 此方法允许从数据库中删除一个教师记录,具体实现需要确定删除的逻辑。
     *
     * @param teacher 需要从数据库中删除的 Teacher 对象
     */
    void deleteTeacher(Teacher teacher);
}
package com.example.demo.service;

import com.example.demo.model.Teacher;
import com.example.demo.mapper.TeacherMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * TeacherService类用于处理教师相关的业务逻辑
 */
@Service
public class TeacherService {

    @Autowired
    private TeacherMapper teacherMapper;

    /**
     * 添加教师信息
     *
     * @param teacher 教师对象,包含要插入数据库的教师信息
     */
    public void addTeacher(Teacher teacher) {
        teacherMapper.insertTeacher(teacher);
    }

    /**
     * 更新教师的电话号码
     *
     * @param teacher 教师对象,包含需要更新电话号码的教师信息
     */
    public void updateTeacherPhoneNumber(Teacher teacher) {
        teacherMapper.updateTeacherPhoneNumber(teacher);
    }

    /**
     * 删除教师信息
     *
     * @param teacher 教师对象,包含需要删除的教师信息
     */
    public void deleteTeacher(Teacher teacher) {
        teacherMapper.deleteTeacher(teacher);
    }
}
package com.example.demo.controller;

import com.example.demo.model.Teacher;
import com.example.demo.service.TeacherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * TeacherController类用于处理与老师相关的HTTP请求
 */
@RestController
@RequestMapping("/teachers")
public class TeacherController {

    /**
     * TeacherService实例,用于调用老师相关的业务逻辑
     */
    @Autowired
    private TeacherService teacherService;

    /**
     * 处理添加老师的请求
     *
     * @param teacher 要添加的老师对象,从请求体中获取
     * @return 添加成功后的提示信息
     */
    @PostMapping("/add")
    public String addTeacher(@RequestBody Teacher teacher) {
        teacherService.addTeacher(teacher);
        return "老师添加成功!";
    }

    /**
     * 处理更新老师电话号码的请求
     *
     * @param teacher 包含需要更新电话号码的老师对象,从请求体中获取
     * @return 更新成功后的提示信息
     */
    @PutMapping("/updatePhone")
    public String updateTeacherPhoneNumber(@RequestBody Teacher teacher) {
        teacherService.updateTeacherPhoneNumber(teacher);
        return "教师电话号码更新成功!";
    }

    /**
     * 处理删除老师的请求
     *
     * @param teacher 要删除的老师对象,从请求体中获取
     * @return 删除成功后的提示信息
     */
    @DeleteMapping("/delete")
    public String deleteTeacher(@RequestBody Teacher teacher) {
        teacherService.deleteTeacher(teacher);
        return "教师删除成功!";
    }
}

动态SQL

动态 SQL 是指在执行 SQL 语句时,根据不同的条件动态生成 SQL 语句。这样可以提高灵活性和适应性,使得 SQL 操作可以根据实际情况进行调整。MyBatis 提供了多种动态 SQL 生成的方式,通过 <if>、<choose>、<foreach>、<where> 和 <trim> 等标签实现。

<if> 标签

if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行

例如,可能需要根据用户是否提供了某些参数来决定是否在 WHERE 子句中包含这些条件。

示例

<mapper namespace="com.example.demo.mapper.TeacherMapper">
    <select id="findTeachers" parameterType="map" resultType="com.example.demo.model.Teacher">
        SELECT * FROM teacher
        <where>
            <!-- 
              条件判断,如果name参数不为空,则添加到WHERE子句中
              作用:通过#{name}占位符动态设置姓名过滤条件
            -->
            <if test="name != null">
                AND name = #{name}
            </if>
            <!-- 
              条件判断,如果email参数不为空,则添加到WHERE子句中
              作用:通过#{email}占位符动态设置电子邮件过滤条件
            -->
            <if test="email != null">
                AND email = #{email}
            </if>
        </where>
    </select>

</mapper>

<choose>, <when>, 和 <otherwise> 标签

choose、when、otherwise相当于if...else if..else

<mapper namespace="com.example.demo.mapper.TeacherMapper">

    <select id="findTeacherByType" parameterType="map" resultType="com.example.demo.model.Teacher">
        SELECT * FROM teacher
        <where>
            <choose>
                <when test="type == 'full-time'">
                    AND employment_type = 'full-time'
                </when>
                <when test="type == 'part-time'">
                    AND employment_type = 'part-time'
                </when>
                <otherwise>
                    AND employment_type IS NOT NULL
                </otherwise>
            </choose>
        </where>
    </select>

</mapper>

<foreach> 标签

<foreach> 标签用于动态生成一个 SQL 片段,适用于处理集合数据,如 IN 子句。

属性:

  • collection:设置要循环的数组或集合
  • item:表示集合或数组中的每一个数据
  • separator:设置循环体之间的分隔符
  • open:设置foreach标签中的内容的开始符
  • close:设置foreach标签中的内容的结束符

示例

<mapper namespace="com.example.demo.mapper.TeacherMapper">

    <select id="findTeachersByIds" parameterType="list" resultType="com.example.demo.model.Teacher">
        SELECT * FROM teacher
        WHERE id IN
        <!-- 对列表中的每个id生成一个元组,将所有元组用逗号分隔 -->
        <foreach item="id" collection="list" open="(" close=")" separator=",">
            #{id}
        </foreach>

    </select>

</mapper>

<where> 标签

<where> 标签用于自动添加 WHERE 关键字,并处理前面的 AND 或 OR 操作符,避免在条件为空时生成多余的 AND。

where和if一般结合使用:

a>若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字

b>若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的
and去掉

注意:where标签不能去掉条件最后多余的and

示例

<mapper namespace="com.example.demo.mapper.TeacherMapper">

    <select id="findTeachers" parameterType="map" resultType="com.example.demo.model.Teacher">
        SELECT * FROM teacher
        <where>
            <if test="name != null">
                name = #{name}
            </if>
            <if test="email != null">
                AND email = #{email}
            </if>
        </where>
    </select>

</mapper>

<trim> 标签

<trim> 标签用于去掉 SQL 语句中多余的前缀或后缀,例如多余的 AND 或 OR。

常用属性:

  • prefix:在trim标签中的内容的前面添加某些内容
  • prefixOverrides:在trim标签中的内容的前面去掉某些内容
  • suffix:在trim标签中的内容的后面添加某些内容
  • suffixOverrides:在trim标签中的内容的后面去掉某些内容

示例

<mapper namespace="com.example.demo.mapper.TeacherMapper">

    <select id="findTeachers" parameterType="map" resultType="com.example.demo.model.Teacher">
        SELECT * FROM teacher
        <trim prefix="WHERE" prefixOverrides="AND |OR ">
            <if test="name != null">
                AND name = #{name}
            </if>
            <if test="email != null">
                AND email = #{email}
            </if>
        </trim>
    </select>

</mapper>

#{}和${}的区别

#{}:用于传递参数值,并自动进行 SQL 注入防护。MyBatis 会将它们替换为参数的占位符,并进行适当的转义。例如:

<select id="findTeacherById" parameterType="int" resultType="Teacher">
    SELECT * FROM teacher WHERE id = #{id}
</select>

这里 #{id} 会被替换为 ?,并在执行时由 MyBatis 安全地绑定参数。

${}:用于直接插入文本或 SQL 片段,不进行任何转义或防护。例子:

<select id="findTeacherByColumn" parameterType="map" resultType="Teacher">
    SELECT * FROM teacher WHERE ${columnName} = #{value}
</select>

如何选择 #{} 和 ${}

  • 使用 #{} 可以有效避免 SQL 注入,特别是在传递参数值时。而 ${} 适用于动态 SQL 片段,如表名或排序字段,但需谨慎使用。
  • @Param 注解确实为参数提供了名称,使得在 SQL 映射文件中可以通过名字来引用参数,更加清晰和安全。

总结:能用 #{} 的地方就用 #{},尽量少用 ${}!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Onlooker﹒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值