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

news/2025/2/5 17:01:14/


一、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/news/1569556.html

相关文章

基序和纯度分数的计算

以下对这两个概念的详细解释&#xff1a; 基序 纯度分数 PWM矩阵的来源 为什么会有PWM矩阵&#xff1f; 一个特定的转录因子&#xff08;TF&#xff09;的结合位点的基序&#xff08;motif&#xff09;并不是唯一的。实际上&#xff0c;TF结合位点通常具有一定的序列变异性&a…

高阶开发基础——快速入门C++并发编程6——大作业:实现一个超级迷你的线程池

目录 实现一个无返回的线程池 完全代码实现 Reference 实现一个无返回的线程池 实现一个简单的线程池非常简单&#xff0c;我们首先聊一聊线程池的定义&#xff1a; 线程池&#xff08;Thread Pool&#xff09; 是一种并发编程的设计模式&#xff0c;用于管理和复用多个线程…

jEasyUI 转换 HTML 表格为数据网格

jEasyUI 转换 HTML 表格为数据网格 引言 随着互联网技术的飞速发展,前端框架和库的应用越来越广泛。jEasyUI 是一款功能强大的 jQuery UI 扩展库,它提供了丰富的 UI 组件,其中数据网格(DataGrid)是 jEasyUI 中一个非常重要的组件。本文将详细介绍如何使用 jEasyUI 将一个…

ASP.NET Core与配置系统的集成

目录 配置系统 默认添加的配置提供者 加载命令行中的配置。 运行环境 读取方法 User Secrets 注意事项 Zack.AnyDBConfigProvider 案例 配置系统 默认添加的配置提供者 加载现有的IConfiguration。加载项目根目录下的appsettings.json。加载项目根目录下的appsettin…

对顾客行为的数据分析:融入2+1链动模式、AI智能名片与S2B2C商城小程序的新视角

摘要&#xff1a;随着互联网技术的飞速发展&#xff0c;企业与顾客之间的交互方式变得日益多样化&#xff0c;移动设备、社交媒体、门店、电子商务网站等交互点应运而生。这些交互点不仅为顾客提供了便捷的服务体验&#xff0c;同时也为企业积累了大量的顾客行为数据。本文旨在…

React第二十七章(Suspense)

Suspense Suspense 是一种异步渲染机制&#xff0c;其核心理念是在组件加载或数据获取过程中&#xff0c;先展示一个占位符&#xff08;loading state&#xff09;&#xff0c;从而实现更自然流畅的用户界面更新体验。 应用场景 异步组件加载&#xff1a;通过代码分包实现组件…

【Java-数据结构】Java 链表面试题下 “最后一公里”:解决复杂链表问题的致胜法宝

我的个人主页 我的专栏&#xff1a;Java-数据结构&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞❤ 收藏❤ 引言&#xff1a; Java链表&#xff0c;看似简单的链式结构&#xff0c;却蕴含着诸多有趣的特性与奥秘&#xff0c;等待我们去挖掘。它就像一…

RabbitMQ快速上手及入门

概念 概念&#xff1a; publisher&#xff1a;生产者&#xff0c;也就是发送消息的一方 consumer&#xff1a;消费者&#xff0c;也就是消费消息的一方 queue&#xff1a;队列&#xff0c;存储消息。生产者投递的消息会暂存在消息队列中&#xff0c;等待消费者处理 exchang…