JavaWeb——Mybatis-基础操作(1/4)-环境准备、删除操作、SQL注入(查看 MyBatis 执行 SQL 语句的方法与预编译 SQL 介绍、预编译 SQL 防范 SQL 注入)

目录

前言

案例需求分析

环境准备

数据库表准备

项目创建与依赖引入

实体类与 Mapper 接口创建

删除功能需求与 SQL 语句分析

MyBatis 中删除功能的实现步骤

Mapper 接口方法定义

单元测试编写与执行

注意事项与技巧

查看 MyBatis 执行 SQL 语句的方法与预编译 SQL 介绍

开启 MyBatis 日志查看执行语句

预编译 SQL 语句原理与优势

SQL 注入与预编译 SQL 防范效果

SQL 注入

预编译 SQL 防范 SQL 注入

MyBatis 中不同占位符的区别与使用建议


前言

MyBatis 基础操作案例需求与环境准备概述

本部分围绕 MyBatis 基础操作展开,首先依据 tlias智能学习辅助系统 员工管理模块的页面原型及需求,明确要实现员工信息的增删改查功能,包括条件分页查询、新增、编辑(查询回显与更新)、单条及批量删除等操作。

随后进行环境准备工作,为后续具体操作奠定基础,这是实现功能的前置关键步骤。

案例需求分析

  1. 查询功能需求
    • 条件分页查询:在员工列表查询时,需依据页面上方的条件(如员工姓名、部门等)进行筛选,并对结果进行分页展示,方便用户查看和管理大量数据。
    • 查询回显:点击编辑按钮时,要先根据主键 ID 将对应员工数据查询出来并展示在表单中,以便用户在原有数据基础上修改。
  2. 新增功能需求:点击新增员工按钮后,在弹出对话框的表单中录入信息,点击保存时,需将数据通过 INSERT 语句插入数据库。
  3. 编辑与更新功能需求:编辑操作先查询回显数据,用户修改后点击保存,执行 UPDATE 语句将修改后的数据更新到数据库。
  4. 删除功能需求
    • 单条删除:点击删除按钮,根据主键 ID 删除对应员工数据。
    • 批量删除:勾选多条数据前的复选框后点击批量删除按钮,删除选中的多条数据。

环境准备

数据库表准备

        执行 EMP(员工表)及相关测试数据的 SQL 语句,创建出 EMP 表并插入 17 条测试数据,同时创建了关联的 DPT(部门表),虽实际操作暂未用到,但保证数据完整性。

-- 部门管理
create table dept
(
    id          int unsigned primary key auto_increment comment '主键ID',
    name        varchar(10) not null unique comment '部门名称',
    create_time datetime    not null comment '创建时间',
    update_time datetime    not null comment '修改时间'
) comment '部门表';

insert into dept (id, name, create_time, update_time)
values (1, '学工部', now(), now()),
       (2, '教研部', now(), now()),
       (3, '咨询部', now(), now()),
       (4, '就业部', now(), now()),
       (5, '人事部', now(), now());


-- 员工管理
create table emp
(
    id          int unsigned primary key auto_increment comment 'ID',
    username    varchar(20)      not null unique comment '用户名',
    password    varchar(32) default '123456' comment '密码',
    name        varchar(10)      not null comment '姓名',
    gender      tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
    image       varchar(300) comment '图像',
    job         tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
    entrydate   date comment '入职时间',
    dept_id     int unsigned comment '部门ID',
    create_time datetime         not null comment '创建时间',
    update_time datetime         not null comment '修改时间'
) comment '员工表';

INSERT INTO emp
(id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time)
VALUES (1, 'jinyong', '123456', '金庸', 1, '1.jpg', 4, '2000-01-01', 2, now(), now()),
       (2, 'zhangwuji', '123456', '张无忌', 1, '2.jpg', 2, '2015-01-01', 2, now(), now()),
       (3, 'yangxiao', '123456', '杨逍', 1, '3.jpg', 2, '2008-05-01', 2, now(), now()),
       (4, 'weiyixiao', '123456', '韦一笑', 1, '4.jpg', 2, '2007-01-01', 2, now(), now()),
       (5, 'changyuchun', '123456', '常遇春', 1, '5.jpg', 2, '2012-12-05', 2, now(), now()),
       (6, 'xiaozhao', '123456', '小昭', 2, '6.jpg', 3, '2013-09-05', 1, now(), now()),
       (7, 'jixiaofu', '123456', '纪晓芙', 2, '7.jpg', 1, '2005-08-01', 1, now(), now()),
       (8, 'zhouzhiruo', '123456', '周芷若', 2, '8.jpg', 1, '2014-11-09', 1, now(), now()),
       (9, 'dingminjun', '123456', '丁敏君', 2, '9.jpg', 1, '2011-03-11', 1, now(), now()),
       (10, 'zhaomin', '123456', '赵敏', 2, '10.jpg', 1, '2013-09-05', 1, now(), now()),
       (11, 'luzhangke', '123456', '鹿杖客', 1, '11.jpg', 5, '2007-02-01', 3, now(), now()),
       (12, 'hebiweng', '123456', '鹤笔翁', 1, '12.jpg', 5, '2008-08-18', 3, now(), now()),
       (13, 'fangdongbai', '123456', '方东白', 1, '13.jpg', 5, '2012-11-01', 3, now(), now()),
       (14, 'zhangsanfeng', '123456', '张三丰', 1, '14.jpg', 2, '2002-08-01', 2, now(), now()),
       (15, 'yulianzhou', '123456', '俞莲舟', 1, '15.jpg', 2, '2011-05-01', 2, now(), now()),
       (16, 'songyuanqiao', '123456', '宋远桥', 1, '16.jpg', 2, '2010-01-01', 2, now(), now()),
       (17, 'chenyouliang', '123456', '陈友谅', 1, '17.jpg', NULL, '2015-03-21', NULL, now(), now());

项目创建与依赖引入

  • 创建新的 Spring Boot 项目,并引入三个关键依赖:Lombok 用于简化实体类定义,MyBatis 实现数据库操作功能,MySQL 驱动包使项目能连接 MySQL 数据库。
  • 在项目的 application.properties 文件中配置数据库连接的四要素,即驱动类名、连接 URL、用户名和密码,确保项目能与数据库建立连接。

实体类与 Mapper 接口创建

  • 创建 EMP 员工实体类,其属性与表结构字段一一对应,遵循驼峰命名规范,如将数据库字段中的下划线分隔形式(如 dpt_id)转换为驼峰形式(dptId),对于日期类型字段,数据库中的 date 类型(入职日期)在实体类中用 LocalDate 类型,datetime 类型(创建时间和修改时间)在实体类中用 LocalDateTime 类型。实体类上添加 @Data@NoArgsConstructor@AllArgsConstructor 等 Lombok 注解,自动生成 getsettoString 等方法及构造函数,简化代码编写。
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
    private Integer id;
    private String username;
    private String password;
    private String name;
    private Short gender;
    private String image;
    private Short job;
    private LocalDate entrydate;
    private Integer deptId;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}
  • 准备 EMP Mapper 接口,并添加 @Mapper 注解,使程序运行时自动创建该接口的代理对象并放入 Spring 的 IoC 容器中,方便后续数据库操作方法的调用与管理。
import org.apache.ibatis.annotations.*;

@Mapper
public interface EmpMapper {

}

删除功能需求与 SQL 语句分析

        在员工管理系统中,点击删除按钮后,前端会将员工数据的主键 ID 传递给后端,后端需依据此 ID 从数据库中删除对应记录。在 SQL 层面,使用 

DELETE FROM EMP WHERE id = [具体 ID 值] 语句实现删除操作,其中 EMP 为员工表,id 是主键。例如,若要删除 ID 为 17 的员工记录,SQL 语句即为

DELETE FROM EMP WHERE id = 17

MyBatis 中删除功能的实现步骤

Mapper 接口方法定义

        在 EMP Mapper 接口中定义 delete 方法,由于删除操作通常无需返回结果给前端(一般只关注操作是否成功执行),故将返回值设为 void。使用 @Delete 注解标注该方法,并在注解的 value 属性中编写 SQL 删除语句。如 @Delete("delete from emp where id = #{id}")

,这里的 ${id} 是 MyBatis 的参数占位符,用于在方法执行时动态传入实际的 ID 值。

单元测试编写与执行

  • 在测试类中,首先通过 @Autowired 注解注入 EMP Mapper 类型的对象,以便在测试方法中调用 delete 方法。

  • 编写单元测试方法 public void testDelete(),并添加 @Test 注解。在方法内部,调用 empMapper.delete(16)(假设当前要删除 ID 为 16 的员工记录)来执行删除操作。

  • 运行单元测试,若测试通过且数据库中对应员工记录被成功删除(可通过刷新数据库查看),则表明删除功能实现正确。

注意事项与技巧

  1. 参数占位符命名规范:在使用 MyBatis 的参数占位符 #{ } 时,若 Mapper 接口方法参数只有一个普通类型参数,占位符 #{ } 内的属性名可随意编写,但在实际项目开发中,建议与方法参数名保持一致,以增强代码可读性和可维护性。例如,方法参数为 int id,占位符写为 #{id} 更符合规范,方便后续代码阅读与理解,避免因随意命名导致的混淆。
  2. 数据库表与项目的同步:在编写 SQL 语句时,如果出现表名无法自动提示的情况,可能是因为数据库表在项目中的缓存未及时更新。此时可在相关操作界面点击刷新按钮,使项目识别新创建或修改的数据库表,确保 SQL 语句编写的准确性和便捷性,避免因表名错误或无法识别导致的操作失败。

查看 MyBatis 执行 SQL 语句的方法与预编译 SQL 介绍

开启 MyBatis 日志查看执行语句

        在 application.properties 配置文件中配置 MyBatis 日志信息并指定输出到控制台,以便查看框架底层执行的 SQL 语句。可通过输入关键字(如 mybatis log)利用 IDEA 提示功能找到相关配置项,如 

mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

开启后运行单元测试,能在控制台看到执行的 SQL 语句及相关信息,如 delete from emp where id =?,其中 ? 为参数占位符。

预编译 SQL 语句原理与优势

在 MyBatis 的 Mapper 接口中使用 #{} 占位符编写 SQL 语句,最终会生成预编译 SQL,#{} 会被替换为 ?。预编译 SQL 具有性能更高和更安全两大优势。

  • 性能优势体现:在数据库执行 SQL 语句时,普通 SQL 语句每次执行都可能需要进行语法检查、解析、优化、编译等操作,若数据量较大且 SQL 语句相似(仅参数不同),如多次执行 delete from emp where id = [不同值]会重复这些操作浪费资源。而预编译 SQL 会将编译后的结果缓存起来,后续相同结构的 SQL 语句执行时可直接使用缓存,减少编译次数,提高执行效率。例如,删除多个员工数据时,预编译 SQL 只需编译一次,大大提升性能。
  • 安全优势体现(防止 SQL 注入):SQL 注入是通过操作输入数据修改 SQL 语句以攻击服务器的方式。例如,在登录验证的 SQL 语句 select count(*) from emp where username = [输入用户名] and password = [输入密码] 中,如果直接将用户输入拼接在 SQL 语句中,恶意用户可通过特殊输入(如在密码框输入 ' or '1'='1)改变 SQL 语句的逻辑,使登录验证绕过。而预编译 SQL 将用户输入作为参数传递,不会将其直接拼接在 SQL 语句中,避免了 SQL 注入风险,保证系统安全。

SQL 注入与预编译 SQL 防范效果

SQL 注入

        考虑如下场景,存在一个学校的图书管理系统,管理员需登录该系统以执行图书管理操作。在正常登录流程中,当管理员输入正确的用户名 “小李” 及密码 “abc123” 后,系统会依据既定逻辑进行验证。此时,在系统后台控制台会生成并执行一条 SQL 语句,其形式为

select count (*) from admin_table where username = ' 小李 ' and password = 'abc123

此语句的作用在于从名为 “admin_table” 的管理员表中精确查找与输入用户名和密码相匹配的用户记录,并统计符合条件的记录数量。若能成功找到匹配记录,则表明登录信息无误,管理员得以顺利登录系统。

        然而,若存在恶意攻击者试图非法侵入该系统,其在密码框中输入诸如 “' or '1'='1” 的特殊字符串。在此情况下,系统后台执行的 SQL 语句将转变为

select count (*) from admin_table where username = ' 随便瞎写的名字 ' and password = '' or '1'='1'

显然,由于 “1=1” 这一条件恒成立,无论实际的用户名与正确密码为何,该查询语句都会返回非零结果。如此一来,系统便会被误导,误判非法用户输入的信息为合法,进而允许其成功登录。通过此例,清晰地展示了 SQL 注入的发生机制与潜在危害,其原理不难理解。

预编译 SQL 防范 SQL 注入

        接下来,我们再来看采用预编译 SQL 的登录项目的情况。同样在登录页面输入之前的恶意数据进行测试,此时在控制台所显示的 SQL 语句呈现为预编译形式,例如 “select count (*) from emp where username =? and password =?”。在这种机制下,用户的输入仅仅是作为参数传递给 SQL 语句,而不会像之前那样被恶意拼接在 SQL 语句之中。

        当输入错误密码时,系统会严格按照预编译 SQL 的逻辑进行验证,不会受到恶意输入的干扰,从而准确地提示登录失败。这充分表明预编译 SQL 有效地阻止了 SQL 注入攻击,切实保障了系统的安全性。

MyBatis 中不同占位符的区别与使用建议

在 MyBatis 中,#{} 和 ${} 是两种不同的占位符。

  1. #{} 占位符:在 SQL 语句执行时,#{} 会被替换为 ?,生成预编译 SQL 语句,主要用于参数传递场景,如根据员工 ID 删除员工信息时 delete from emp where id = #{id},能提高性能并防止 SQL 注入,是项目开发中常用的占位符。
  2. ${} 占位符${} 是直接将参数拼接在 SQL 语句中,如 select * from ${tableName},一般用于对表名或字段名进行动态设置,但这种方式存在 SQL 注入风险且性能较低。在实际项目中,除非有特殊需求(如动态切换表名等极个别情况),否则应尽量避免使用 ${} 占位符。因为其带来的安全隐患和性能问题可能会对系统造成严重影响。在大多数常规的数据库操作中,如数据的增删改查操作里的参数传递环节,都应优先选择 #{} 占位符,以确保系统的高效与安全运行。

END 


学习自:黑马程序员——JavaWeb课程 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值