【JavaEE】Spring(6):Mybatis(下)

ops/2025/2/5 13:11:27/


一、Mybatis XML配置文件

Mybatis开发有两种方式:

  1. 注解
  2. XML

之前讲解了注解的方式,接下来学习XML的方式

1.1 配置数据库连接和Mybatis

直接在配置文件中配置即可:

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
mybatis:configuration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl mapper-locations: classpath:mapper/**Mapper.xml #配置xml文件的路径

UserInfoXMLMapper.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.UserInfoXMLMapper"><select id="queryAllUser" resultType="com.example.demo.model.UserInfo">select username,`password`, age, gender, phone from userinfo</select></mapper>

测试代码:

@Test
void queryAllUser() {userInfoMapper.queryAllUser();
}

1.2 增(Insert)

xml文件:

<insert id="insertUser">insert into userinfo (username, `password`, age, gender, phone) values (#{username}, #{password}, #{age},#{gender},#{phone})
</insert>

UserInfoXMLMapper接口:

Integer insertUser(UserInfo userInfo);

返回结果是影响的行数

返回自增id:

<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">insert into userinfo (username, `password`, age, gender, phone) values (#{username}, #{password}, #{age},#{gender},#{phone})
</insert>

1.3 删(Delete)

xml文件:

<delete id="deleteUser">delete from userinfo where id = #{id}
</delete>

1.4 改(Update)

xml文件:

<update id="updateUser">update userinfo set username=#{username} where id=#{id}
</update>

1.5 查(Select)

在使用注解查询所有用户时,会遇到有属性没有被赋值的情况,我们的解决方案分别为:起别名、结果映射、 列名驼峰式命名

现在使用xml文件,解决方案仍然是这三个,其中第1个和第3个和注解的方式一样,这里主要讲解以下结果映射

<resultMap id="BaseMap" type="com.example.demo.model.UserInfo"><id column="id" property="id"></id><result column="delete_flag" property="deleteFlag"></result><result column="create_time" property="createTime"></result><result column="update_time" property="updateTime"></result>
</resultMap>
<select id="queryAllUser" resultType="com.example.demo.model.UserInfo" resultMap="BaseMap">select id, username,`password`, age, gender, phone, delete_flag, create_time, update_time from userinfo
</select>

二、#{} 和 ${}的区别

#{}和${}都可以用来赋值,我们之前都用的#{},接下来看以下这两个的区别

1. 赋值的是Integer类型

首先是#{}

<select id="selectUserById" resultType="com.example.demo.model.UserInfo">select username, password, age, gender, phone from userinfo where id = #{id}
</select>

观察日志:

我们输入的参数并没有拼接到SQL语句中,而是用?作为占位符,我们称这种SQL为预编译型SQL

现在改成${}

<select id="selectUserById" resultType="com.example.demo.model.UserInfo">select username, password, age, gender, phone from userinfo where id = ${id}
</select>

此时我们输入的参数拼接到了SQL语句中

2. 赋值的是String类型

首先是#{}

<select id="selectUserByName" resultType="com.example.demo.model.UserInfo">select username, password, age, gender, phone from userinfo where username = #{username}
</select>

改为${}

<select id="selectUserByName" resultType="com.example.demo.model.UserInfo">select username, password, age, gender, phone from userinfo where username = ${username}
</select>

由于SQL语法中,字符串类型需要加上单引号,将参数直接拼接到SQL语句中是没有加单引号的,因此会报错

所以要在xml中手动加上单引号

${}存在SQL注入问题

SQL注入:通过输入的数据来修改事先定义好的SQL语句,以达到执行代码共计服务器的方式

举例:查询名字为 lisi 的用户信息,正常情况要手动加上单引号

我们输入lisi后,就可查到他的信息,但如果将输入改为 'or 1 = '1 ,将该参数拼接到SQL语句后:

可以看到通过这个查询条件可以查询到所有用户的信息

如果将密码验证的代码简单的写成 password = '${password}',此时如果密码写 'or 1 = '1,就可以直接登录成功

2.1 排序功能

${}存在SQL注入问题,但也不是一点没用,其中排序就需要用到${}

<select id="selectAllUserBySort" resultType="com.example.demo.model.UserInfo">select username, password, age, gender, phone from userinfo order by id ${sort}
</select>

执行测试代码

@Test
void selectAllUserBySort() {userInfoXMLMapper.selectAllUserBySort("desc");
}

如果使用#{},由于参数类型为String,在查询时,desc前后会自动加上单引号,但排序并不需要单引号,所以会出错

2.2 like 查询

like 使用#{}报错

@Select("select id, username, age, gender, phone, delete_flag, create_time,
update_time from userinfo where username like '%#{key}%' ")
List<UserInfo> queryAllUserByLike(String key);

把 #{} 改成 ${} 可以正确查出来,但是 ${} 存在SQL注⼊的问题,所以不能直接使⽤ ${}
解决方法:使⽤ mysql的内置函数concat()来处理,实现代码如下:

@Select("select id, username, age, gender, phone, delete_flag, create_time,
update_time from userinfo where username like concat('%',#{key},'%')")
List<UserInfo> queryAllUserByLike(String key);

三、动态SQL

1.1 <if>标签

<if>标签的作用:动态拼接

<insert id="insertUserByCondition">insert into userinfo (username,`password`,age,<if test="gender != null">gender,</if>phone)values (#{username},#{age},<if test="gender != null">#{gender},</if>#{phone})
</insert>

上述代码:如果gender不为空,则会将其拼接到SQL语句中(也就是我们在传参时,传了gender这个参数)

1.2 <trim>标签

<trim>标签的作用:添加或删除前缀和后缀

刚才我们只有一个选填字段,事实上可能有多个:

<insert id="insertUserByCondition">INSERT INTO userinfo<trim prefix="(" suffix=")" suffixOverrides=","><if test="username !=null">username,</if><if test="password !=null">`password`,</if><if test="age != null">age,</if><if test="gender != null">gender,</if><if test="phone != null">phone,</if></trim>VALUES<trim prefix="(" suffix=")" suffixOverrides=","><if test="username !=null">#{username},</if><if test="password !=null">#{password},</if><if test="age != null">#{age},</if><if test="gender != null">#{gender},</if><if test="phone != null">#{phone}</if></trim>
</insert>

trim标签中:

  • prefix:以prefix的值作为整个语句块的前缀
  • suffix:以suffix的值作为整个语句块的后缀
  • prefixOverrides:表示整个语句块要去除的前缀
  • suffixOverrides:表示整个语句块要去除的后缀,在上述代码中最后拼接的字段可能结尾带有逗号,所以加上suffixOverrides

1.3 <where>标签

看下图,有时条件也需要动态拼接:

<where>标签的主要作用:动态拼接条件

<select id="queryByCondition" resultType="com.example.demo.model.UserInfo">select id, username, age, gender, phone, delete_flag, create_time, update_time from userinfo<where><if test="age != null">and age = #{age}</if><if test="gender != null">and gender = #{gender}</if><if test="deleteFlag != null">and delete_flag = #{deleteFlag}</if></where>
</select>

<where>标签还有两个作用:

  1. 如果没有判断条件,where会自动去除
  2. 如果第一个条件有前缀and或or,<where>标签也会自动去除

1.4 <set>标签

<set>标签的作用:动态指定更新的内容

<update id="updateUserByCondition">update userinfo<set><if test="username != null">username = #{username},</if><if test="age != null">age = #{age},</if><if test="deleteFlag != null">delete_flag = #{deleteFlag},</if></set>where id = #{id}
</update>

<set>标签可以自动删除额外的逗号

1.5 <foreach>标签

<foreach>标签的作用:对集合进行遍历

批量删除:

Integer deleteByIds(List<Integer> ids);
<delete id="deleteByIds">delete from userinfowhere id in<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach>
</delete>
  • collection:绑定方法参数中的集合,也就是要遍历的集合
  • item:遍历的每一个对象
  • separator:每次遍历之间间隔的字符串
  • open:整个语句块开头的字符串
  • close:整个语句块结尾的字符串

1.6 <include>标签

在xml文件中配置的SQL有许多重复的片段

解决方法:将重复的sql片段提取出来放在<sql>标签,然后通过<include>标签复用

<sql id="allColumn">username, password, age, gender, phone
</sql>
<select id="selectUserById" resultType="com.example.demo.model.UserInfo">select<include refid="allColumn"></include>from userinfo where id = ${id}
</select>

🙉本篇文章到此结束


http://www.ppmy.cn/ops/155874.html

相关文章

《苍穹外卖》项目学习记录-Day7缓存菜品

我们优先去读取缓存数据&#xff0c;如果有就直接使用&#xff0c;如果没有再去查询数据库&#xff0c;查出来之后再放到缓存里去。 微信小程序根据分类来展示菜品&#xff0c;所以每一个分类下边的菜品对应的就是一份缓存数据&#xff0c;这样的话当我们使用这个数据的时候&am…

RESTful API的设计原则与这些原则在Java中的应用

RESTful API 是基于 REST&#xff08;Representational State Transfer&#xff09; 架构风格设计的 API&#xff0c;其核心目标是提高系统的可伸缩性、简洁性和可维护性。以下是 RESTful API 的设计原则及在 Java 中的实现方法&#xff1a; 一、RESTful API 的核心设计原则 客…

98,【6】 buuctf web [ISITDTU 2019]EasyPHP

进入靶场 代码 <?php // 高亮显示当前 PHP 文件的源代码&#xff0c;通常用于调试或展示代码&#xff0c;方便用户查看代码逻辑 highlight_file(__FILE__);// 从 GET 请求中获取名为 _ 的参数值&#xff0c;并赋值给变量 $_ // 符号用于抑制可能出现的错误信息&#xff…

全栈开发:使用.NET Core WebAPI构建前后端分离的核心技巧(一)

目录 cors解决跨域 依赖注入使用 分层服务注册 缓存方法使用 内存缓存使用 缓存过期清理 缓存存在问题 分布式的缓存 cors解决跨域 前后端分离已经成为一种越来越流行的架构模式&#xff0c;由于跨域资源共享(cors)是浏览器的一种安全机制&#xff0c;它会阻止前端应用…

kubernetes-部署性能监控平台

在当今快速发展的云计算时代&#xff0c;Kubernetes 已成为容器编排的事实标准。随着越来越多的应用迁移到 Kubernetes 平台上&#xff0c;如何有效地监控集群的健康状态、资源使用情况以及应用性能变得尤为重要。一个完善的监控系统可以帮助我们及时发现问题、优化资源配置&am…

02.01、移除重复节点

02.01、[简单] 移除重复节点 1、题目描述 编写代码&#xff0c;移除未排序链表中的重复节点。保留最开始出现的节点。 2、解题思路 为了实现这一目标&#xff0c;我们可以使用一个哈希表&#xff08;或集合&#xff09;来记录已经遇到的节点值&#xff0c;逐步遍历链表并删…

每日一题——滑动窗口的最大值

滑动窗口的最大值 题目描述示例说明 解题思路双端队列的特点实现步骤代码实现&#xff08;C语言&#xff09;代码解析 总结 题目描述 给定一个长度为 n 的数组 num 和滑动窗口的大小 size&#xff0c;找出所有滑动窗口里数值的最大值。 例如&#xff0c;如果输入数组 {2, 3, …

mac 手工安装OpenSSL 3.4.0

如果你希望继续安装 openssl-3.4.0 而不是降级到 3.1.1&#xff0c;可以尝试以下解决方案。根据你提供的错误信息&#xff0c;问题可能出在测试阶段&#xff08;make test&#xff09;&#xff0c;我们可以尝试跳过测试或修复测试失败的原因。 --- ### **解决方案&#xff1a…