文章目录
- 一.MyBatis的模式开发
- 1.1 定义数据表和实体类
- 1.2 配置数据源和MyBatis
- 1.3 编写Mapper接口和增加xxxMapper.xml
- 1.4 测试我们功能的是否实现.
- 二. Mybatis的增删查改操作
- 2.1 单表查询
- 2.2 多表查询
- 三.动态SQL的实现
- 3.1 什么是动态SQL
- 3.2 动态SQL的使用
- if标签的使用
- trim标签的使用
- where标签的使用
- set标签的使用
- foreach标签的使用
- 3.3 综合练习
一.MyBatis的模式开发
我们在开始MyBatis模式开发之前,我们首先来了解一下mybaits在整个框架的定位.看下图可知
MyBatis 也是一个ORM框架,ORM(Object Relational Mapping) ,即对象关系映射。在面向对象编程语言中,将关系型数据库中的数据与对象建立起映射关系,进而自动的完成数据与对象的互相转换:
1.将输入数据(即传入对象)+SQL映射成原生SQL
2.将结果集映射为返回对象,即输出对象
也就是说使⽤ MyBatis 可以像操作对象⼀样来操作数据库中的表,可以实现对象和数据库表之间
的转换,接下来我们来看 MyBatis 的使⽤吧.
使用过程中,还需要按照后端工程师的思路,来实现查询所有用户的功能.
1.1 定义数据表和实体类
创建数据表
CREATE TABLE `userinfo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) NOT NULL,
`password` varchar(32) NOT NULL,
`photo` varchar(500) DEFAULT '',
`createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updatetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`state` int(11) DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4
创建实体类
@Data
public class UserEntity {
private Integer id;
private String username;
private String pwd;
private String photo;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
1.2 配置数据源和MyBatis
在application.properties中配置以下内容
# mysql的配置文件
spring.datasource.url=jdbc:mysql://localhost:3306/mycnblog?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
driver.class.driver-class-name=com.mysql.jdbc.Driver
#配置 MyBatis 中的 XML 路径
# 1.保存路径 2.xml格式
mybatis.mapper-locations=classpath:mybatis/**Mapper.xml
1.3 编写Mapper接口和增加xxxMapper.xml
我们现来实现查询所有用户的功能.
定义接口UserMapper接口:
@Mapper注解代表一个Mapper
@Mapper
public interface UserMapper {
public List<UserEntity> getAll();}
定义UserMapper.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.UserMapper">\
<select id="getAll" resultType="com.example.demo.entity.UserEntity">
select*from userinfo
</select>
</mapper>
针对以上标签进行说明
标签:需要指定namespace 属性,表示命名空间,值为 mapper接口的全限定名,包括全包名.类名。
查询标签:是用来执行数据库的查询操作的:
id:是和Interface (接口)中定义的方法名称一样的,表示对接口的具体实现方法。
resultType:是返回的数据类型,也就是开头我们定义的实体类。
1.4 测试我们功能的是否实现.
我们会引入一个单元测试的概念,我们每实现一个功能没必要,都要去启动项目,然后去验证,这时候我们就可以启动单元测试.
在springboot中启动单元测试也是比较简单的事情,具体的步骤如下:
-
在要测试的类上石健Generate…
-
在测试方法中加上@SpringBootTest注解
直接执行此方法,得出查询结果.
二. Mybatis的增删查改操作
我们在知道了基本的Mybatis的流程,我们来进行基本的增删改查操作
2.1 单表查询
UserMapper接口文件
//根据id查询对象
UserEntity getUserById(@Param("id") Integer id);
//根据名称查询用户对象
UserEntity getUseByUserName(@Param("username")String username);
// 登录方法
UserEntity login(UserEntity user);
// 修改密码
int updatePassword(@Param("id") Integer id,
@Param("password") String password,
@Param("newpassword") String newPassword);
//删除操作
int delById(@Param("id") Integer id);
//增加用户
int addUser(UserEntity user);
//得到用户id
int addUserGetID(UserEntity user);
//根据用户模糊查询
List<UserEntity> getListByName(@Param("username")String username);
Usermapper.xml文件
<select id="getUserById" resultType="com.example.demo.entity.UserEntity">
select * from userinfo where id=#{id}
</select>
<select id="getUseByUserName" resultType="com.example.demo.entity.UserEntity">
select * from userinfo where username=${username}
</select>
<select id="login" resultType="com.example.demo.entity.UserEntity">
select * from userinfo where username= '${username}' and password= '${password}'
</select>
<update id="updatePassword">
update userinfo set password=#{newpassword}
where id = #{id} and password=#{password}
</update>
<delete id="delById">
delete from userinfo where id=#{id}
</delete>
<insert id="addUser">
insert into userinfo(username,password) values(#{username},#{password})
</insert>
<insert id="addUserGetID" useGeneratedKeys="true" keyProperty="id">
insert into userinfo(username,password) values(#{username},#{password})
</insert>
<select id="getListByName" resultMap="BaseMap">
select id,username,password as pwd from userinfo where username like concat('%',#{username},'%')
</select>
这上面有参数占位符,具体的解释如下;
#预编译处理。
$:字符直接替换。
预编译处理是指:MyBatis在处理f时,会将SQL 中的州替换为?号,使用PreparedStatement的set方法来赋值。
直接替换:是MyBatis 在处理$时,就是把$替换成变量的值。
这里来说明一下预编译处理和字符串直接替换
预编译处理(Prepared Statement)和字符串替换(String Replacement)是两种不同的数据库查询参数传递方式,它们在性能和安全性方面有着明显的区别。
预编译处理(Prepared Statement):
预编译处理是一种参数化查询的方式,在查询语句中使用占位符(通常是问号 “?”)来表示参数。
在执行预编译处理时,数据库会将SQL语句和参数分开处理,首先将SQL语句编译成一个准备好的查询模板,然后再将参数传递到模板中执行。
预编译处理将SQL语句与参数分开,因此能够有效地防止SQL注入攻击,提高了查询性能和安全性。
由于数据库在执行查询前已经对SQL语句进行了编译,所以对于多次执行相同查询但参数不同的情况,预编译处理能够提高性能,因为数据库可以重复使用相同的查询模板。
字符串替换(String Replacement):
字符串替换是一种直接将参数值嵌入到SQL语句中的方式。在查询语句中,直接将参数值拼接到SQL语句中的相应位置。
字符串替换的查询方式容易受到SQL注入攻击,因为恶意用户可以在参数值中插入恶意的SQL代码,破坏数据库或获取敏感数据。
由于字符串替换是每次执行查询都会生成一个新的SQL语句,所以对于相同查询的多次执行,每次都需要重新编译和执行,性能相对较低。
具体来说的话,我们来看下面的图示:
不知道大家注意到没有.上面的字符串替换,为什么会出现SQL注入问题,这里我用一张图给大家去解释
2.2 多表查询
在进行多表联查之前,我们还需要准备一个文章表
CREATE TABLE `articleinfo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL,
`content` text NOT NULL,
`createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updatetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`uid` int(11) NOT NULL,
`rcount` int(11) NOT NULL DEFAULT '1',
`state` int(11) DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 |
插入了几条数据:
文章表的内容:
用户表的内容:
多表查询的接口类如下:
@Mapper
public interface ArticleMapper {
//查询文章详情 一对一,一篇文章最多有一个作者
ArticleInfoVO getDetail(@Param("id") Integer id);
List<ArticleInfoVO> getArticleByUid(@Param("uid") Integer uid);
}
配置文件如下:
<select id="getDetail" resultType="com.example.demo.entity.vo.ArticleInfoVO">
select a.*,u.username from articleinfo a
left join userinfo u on u.id=a.uid
where a.id=#{id}
</select>
<select id="getArticleByUid" resultType="com.example.demo.entity.vo.ArticleInfoVO">
select a.* ,u.username from articleinfo a
left join userinfo u on u.id = a.uid
where a.uid=#{uid}
</select>
三.动态SQL的实现
3.1 什么是动态SQL
动态sql 是Mybatis的强大特性之一,能够完成不同条件下不同的sql拼接。
当然官网对其的解释入下:
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
3.2 动态SQL的使用
if标签的使用
if标签用于在SQL语句中根据条件判断是否包含某个SQL片段。语法如下:
<select id="getUsers" resultType="User">
SELECT * FROM users
<where>
<if test="name != null">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
在上面的例子中,根据传入的name和age参数的值,如果它们不为空,就会拼接对应的SQL条件,实现动态的查询语句。
trim标签的使用
trim标签用于在SQL语句的头部或尾部去除多余的SQL片段,以避免不必要的SQL语法错误。trim标签还可以根据条件去除WHERE或AND等关键字,以确保动态SQL的正确性。
trim标签中有如下属性:
prefix:表示整个语句块,以prefix的值作为前缀
suffix:表示整个语句块,以suffix的值作为后缀.
prefixOverrides:表示整个语句块要去除掉的前缀.
suffixOverrides:表示整个语句块要去除掉的后缀
<select id="getUsers" resultType="User">
SELECT * FROM users
<trim prefix="WHERE" prefixOverrides="AND | OR">
<if test="name != null">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
<if test="gender != null">
AND gender = #{gender}
</if>
</trim>
</select>
在上面的例子中,我们使用了trim标签来包裹if标签,prefix属性指定了在条件满足时在WHERE关键字之前添加"WHERE",prefixOverrides属性指定了当条件不满足时去除多余的"AND "或"OR "。
where标签的使用
where标签用于在SQL语句中包含WHERE子句,并根据条件动态拼接查询条件。
<select id="getUsers" resultType="User">
SELECT * FROM users
<where>
<if test="name != null">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
set标签的使用
根据传⼊的⽤户对象属性来更新⽤户数据,可以使⽤标签来指定动态内容。
UserMapper 接⼝中修改⽤户⽅法:根据传⼊的⽤户 id 属性,修改其他不为 null 的属性:
<update id="updateUser" parameterType="User">
UPDATE users
<set>
<if test="name != null">
name = #{name},
</if>
<if test="age != null">
age = #{age},
</if>
</set>
WHERE id = #{id}
</update>
foreach标签的使用
foreach的属性如下所示:
collection:绑定方法参数中的集合,如List,Set,Map或数组对象item:遍历时的每一个对象
open:语句块开头的字符串close:语句块结束的字符串
separator:每次遍历之间间隔的字符串
foreach标签用于在SQL语句中遍历集合,生成对应的SQL片段。它常用于批量插入或更新操作。
<delete id="delByIdList">
<!-- where id in(1,2..)-->
delete from articleinfo
where id in
<foreach collection="idList" item="aid" open="(" close=")" separator=",">
#{aid}
</foreach>
</delete>
这上面生成的语句,入下所示
delete from articleinfo where id in (1, 2, 3)
3.3 综合练习
在我们了解了基本的动态SQL标签之后,我们来一个综合的练习.
假设我们假如我们传入的参数都是非必须的.我们怎么才能完成SQL的拼接.
SQL如下:
select * from articleinfo WHERE id=? and title like concat(‘%’,?,‘%’)
我们传入参数的情况如下:
1.传入id,不传入title
2.传入title,不传入id
3.两个都不传
动态SQL的拼接策略如下:
方案一:
<select id="getListByIdOrTitle" resultType="com.example.demo.entity.vo.ArticleInfoVO">
select * from articleinfo
where 1=1
<trim prefixOVerrides="and">
<if test="id!=null and id>0">
and id=#{id}
</if>
<if test="title!=null and title!=''">
and title like concat('%',#{title},'%')
</if>
</trim>
</select>
trim prefixOVerrides=“and”: 这是MyBatis的动态SQL标签trim的使用。trim标签用于在SQL语句的头部或尾部去除多余的SQL片段,并可以根据条件去除特定的关键字,如这里的and。prefixOverrides属性指定了当条件不满足时去除的前缀关键字,这里是and,表示如果条件不满足,就去除SQL语句中多余的and关键字。
方案二:
<select id="getListByIdOrTitle" resultType="com.example.demo.entity.vo.ArticleInfoVO">
select * from articleinfo
<trim prefix ="where" suffixOverrides="and">
<if test="id!=null and id>0">
id=#{id}
</if>
<if test="title!=null and title!=''">
and title like concat('%',#{title},'%')
</if>
</trim>
</select>
中间解释:
trim prefix=“where” suffixOverrides=“and”>: 这是MyBatis的动态SQL标签trim的使用。trim标签用于在SQL语句的头部或尾部去除多余的SQL片段,并可以根据条件去除特定的关键字,如这里的and。prefix属性指定了在条件满足时在WHERE关键字之前添加"where",suffixOverrides属性指定了当条件不满足时去除SQL语句中多余的"and"。
方案三:
<select id="getListByIdOrTitle" resultType="com.example.demo.entity.vo.ArticleInfoVO">
select * from articleinfo
<where>
<if test="id!=null and id>0">
id=#{id}
</if>
<if test="title!=null and title!=''">
and title like concat('%',#{title},'%')
</if>
</where>
</select>
where标签: 这是MyBatis的动态SQL标签的使用。where标签的作用是将包含在其中的条件片段包裹在WHERE子句中,如果条件满足,WHERE关键字和多余的AND或OR将会被自动添加,如果条件不满足,则WHERE关键字也不会出现在最终的查询语句中