MyBatis的增删改查操作

简介: 这篇文章,我们就来完成MyBatis的增删改查操作,体会高级框架带来的灵活与简便。

1.增加操作


1.1 添加用户并返回受影响的行数


1、 在mapper包下(interface)添加方法声明.


微信图片_20230111212804.png

2、在xml实现添加业务


微信图片_20230111212801.png

3、 单元测试


微信图片_20230111212757.png

测试结果:


微信图片_20230111212754.png

微信图片_20230111212745.png


1.2 添加用户并返回自增ID


1、添加方法声明


微信图片_20230111212738.png

2、在xml实现添加业务


微信图片_20230111212733.png

useGeneratedKeys:这会令MyBatis使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键(比如:像MySQL和SQL Server这样的关系型数据库管理系统的自动递增字段),默认值:false。

keyColumn:设置生成键值在表中的列名,在某些数据库(像PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。

keyPropety:指定能够唯一识别对象的属性,MyBatis会使用getGeneratedKeys的返回值或insert语句中的selectKey子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性的名称。

3.单元测试


微信图片_20230111212729.png

注解@Transactional表示该事务在测试完成后会自动回滚,这也是单元测试的优点,不会污染数据库。

测试结果:


微信图片_20230111212723.png

2.删除操作


1、在mapper(interface)里面添加删除的代码声明


微信图片_20230111212720.png

注解@Param中的参数需要与xml中的参数对应。


2.在xml中添加< delete >标签和删除的sql


微信图片_20230111212716.png

3.单元测试


微信图片_20230111212713.png

测试结果:


微信图片_20230111212709.png

3.修改操作


1、在mapper(interface)里面添加修改的代码声明


微信图片_20230111212705.png

2、在xml中添加< update >标签和具体要执行的SQL


微信图片_20230111212700.png

3.单元测试

微信图片_20230111212656.png

测试结果:


微信图片_20230111212653.png

4.查找操作


4.1 单表查询


4.1.1 参数占位符#{}和${}


#{}:预编译处理

${}:字符直接替换

预编译处理是指:MyBatis在处理#{}时,会将SQL中的#{}替换为?号,使用PreparedStatement的set方法来赋值。


直接替换是指:MyBatis在处理$ {}时,就直接把${}替换成变量的值。


下边通过几个例子来具体了解一下两者的差别:


针对int类型的参数进行查询


微信图片_20230111212648.png

使用#{},可以在测试结果中发现,就是把#{}替换成了?占位符,进行预编译处理。


微信图片_20230111212644.png

微信图片_20230111212637.png


微信图片_20230111212634.png


使用${},可以在测试结果中发现,就直接把 ${}替换成变量的值。


微信图片_20230111212632.png

微信图片_20230111212628.png


微信图片_20230111212625.png


但是针对int类型的参数两种占位符都完成了查询,下边我们来看

针对String类型的参数进行查询

微信图片_20230111212622.png

使用#{}参数占位符


微信图片_20230111212619.png

微信图片_20230111212616.png


微信图片_20230111212607.png


使用${}参数占位符


微信图片_20230111212602.png

微信图片_20230111212558.png

微信图片_20230111215909.png



发现在使用${}占位符去进行查询时,会发生报错,这是因为通过#{}占位符去进行查询的时候,默认加上了单引号,拼装的SQL就成了select * from userinfo where username='张三',而通过 ${}占位符去进行查询的时候直接替换但并没有加上单引号,拼装的SQL就成了select * from userinfo where username=张三,所以会SQL报错。


总结

#{}和${}的区别


1.定义不同:#{}是预处理;而${}是直接替换

2.使用不同:#{}适用于所有类型的参数匹配;但 ${}只适用于数值类型。

3.安全性不同:#{}安全性能高,没有安全问题;但 ${}存在SQL注入和越权等安全问题。


越权分为垂直越权和水平越权,比如一个用户信息管理系统有用户和管理员两种角色,如果用户A能够操作用户B的信息,这就是水平越权;如果用户能够使用管理员才具有的功能,这就是垂直越权。


4.1.2 ${}的使用场景


虽然${}占位符的使用受限,但是其也有它无可替代的使用场景,当传递的是一个SQL关键字(SQL命令)的时候,只能使用 ${},此时如果使用#{}就会认为传递的为一个普通的值,而非SQL命令,所以执行就会报错。


就像下边这个例子,会有价格从低到高或者从高到低的排序,如果想要实现这样的效果,就需要使用到${}占位符


微信图片_20230111212547.png

代码示例:


微信图片_20230111212544.png


微信图片_20230111212541.png


测试:

微信图片_20230111212534.png


微信图片_20230111212531.png


4.1.3 SQL注入问题


下边通过一个登录的案例来引入SQL注入的问题:


微信图片_20230111212525.png

微信图片_20230111212523.png

微信图片_20230111212514.png

微信图片_20230111212510.png


我们可以发现,当我输入的密码为' or 1='1时,经过拼装出来的SQL是select * from userinfo where username='admin' and password='' or 1='1',这样即使不知道密码,也能返回该用户的信息,这就是SQL注入问题。


要想解决${}参数占位符带来的SQL注入问题,就需要在业务层对传递的值进行安全效验,如4.1.2中的排序,就需要规定传入的参数只能为asc或者desc,也就是说想要用 ${}参数占位符,需要该位置的参数是可穷举的,那么这个4.1.3中登录的例子也就不适用了,所以其更适用于用#{}来解决登录的问题。


微信图片_20230111212506.png

微信图片_20230111212504.png


可以发现用#{}参数占位符去搜索时,查询不到结果,也就解决了该安全隐患。


4.1.4 like模糊查询


这是一个特殊的查询,如果使用#{}会报错,但使用${}在业务层的值又不能穷举,就需要通过SQL中的concat函数,将%与模糊字符合并起来,如下所示。


微信图片_20230111212459.png

微信图片_20230111212457.png

微信图片_20230111212452.png

微信图片_20230111212447.png


4.2 多表查询

如果是增、删、改操作,返回受影响的行数,那么在mapper.xml中是可以不设置返回的类型的,如下图所示:


微信图片_20230111212444.png

但即使如果是最简单的查询操作,也需要设置返回类型,否则就会报错。也就是说对于< select >查询标签来说,至少需要两个属性:


id属性:用于标识实现接口中的那个方法

结果映射属性:结果映射有两种实现标签;< resultMap >和< resultType >。

4.2.1 返回类型:resultType


绝大多数查询场景可以使用resultType进行返回,如下代码所示:


微信图片_20230111212439.png

其优点是使用方便,直接定义到某个实体类即可。


4.2.2 返回字典映射:resultMap


resultMap使用场景:


字段名称和程序中的属性名不同的情况,可以使用resultMap配置映射;

一对一和一对多关系可以使用resultMap映射并查数据

字段名和属性名不同的情况:


微信图片_20230111212434.png

mapper.xml中的代码:


微信图片_20230111212431.png

单元测试代码:


微信图片_20230111212426.png

单元测试结果:


微信图片_20230111212422.png

查询不到name属性,这时候就需要用到resultMap了,resultMap的使用如下:


微信图片_20230111212419.png

微信图片_20230111220852.png

查询成功:


微信图片_20230111212411.png

4.2.3 多表查询


在多表查询时,如果使用resultType标签,在一个类中包含了另一个对象,是查询不出来被包含的对象的,比如以下实体类:一篇文章对应一个作者,文章实体类中包含对象实体。


微信图片_20230111212406.png

mapper.xml代码如下:


微信图片_20230111212402.png

测试代码如下:


微信图片_20230111212358.png

测试结果:

微信图片_20230111221022.png

此时,我们就需要使用特殊的手段来实现联表查询了。


一对一的表映射

一对一映射要使用< association >标签,具体实现如下(一篇文章只对应一个作者):


微信图片_20230111212354.png

以上使用< association >标签,表示一对一的结果映射:


property属性:指定Article中对应的属性,即用户。

resultMap属性:指定关联的结果集映射,将基于该映射配置来组织用户数据。

columnPrefix属性:如遇多表中有相同字段名时,该属性作为区分不同表中相同字段的前缀。


映射的mapper.xml文件如下:


微信图片_20230111212350.png

测试代码如下:


微信图片_20230111212346.png

测试结果:

微信图片_20230111221137.png


一对多的表映射

一对多需要使用< collection >标签,用法和< association >相同,如下所示:(一个用户对应多篇文章)

微信图片_20230111212235.png

微信图片_20230111212229.png


测试结果:

微信图片_20230111212226.png


5.动态SQL


5.1 < if >标签


我们在进行注册功能时,可能涉及到必填字段和非必填字段两类字段,那如果在添加用户的时候,有不确定的字段传入,程序此时就应该使用动态标签< if >来判断了,该标签的主要作用是判断一个参数是否有值,如果没值,那么会隐藏if中的SQL,如下的photo字段。


微信图片_20230111212221.png

拼装的SQL就会根据是否传入了photo参数来确定是否增添photo字段。


微信图片_20230111212218.png

5.2 < trim >标签


之前的插入用户功能,只有一个photo字段可能是选填项,如果所有字段都是非必填项,就考虑使用< trim >标签结合< if >标签,对多个字段都采取动态生成的方式。最主要的作用就是:去除SQL语句前后多余的某个字符


prefix:表示整个语句块,以prefix的值作为前缀

suffix:表示整个语句块,以suffix的值作为后缀

prefixOverrides:表示整个语句块要去除掉的前缀

suffixOverriders:表示整个语句块要去除的后缀

调整UserMapper.xml的插入语句为:


微信图片_20230111212211.png

测试结果:

微信图片_20230111212208.png


5.3 < where >标签


该标签的主要作用是:

实现查询中的where SQL替换,如果没有任何的查询条件,那么它可以隐藏查询查询中的where SQL,但如果存在查询条件,那么就会生成where的SQL查询;并且使用where标签可以自动的去除最前面的一个and字符


mapper.xml中的代码如下:

微信图片_20230111212204.png

测试结果:


微信图片_20230111212145.png

以上< where >标签也可以使用< trim prefix="where" prefixOverrides="and" >替换。


5.4 < set >标签


该标签的主要作用是:

进行修改操作时,配合if来处理非必传参数,它的特点是会自动去除最后一个英文逗号。


mapper中的代码如下


微信图片_20230111212125.png

mapper.xml中的代码如下:


微信图片_20230111212120.png

测试及测试结果如下:


微信图片_20230111212116.png

以上< set >标签也可以使用< trim prefix="set" suffixOverrides="," >替换


5.5 < foreach >标签


对集合进行遍历时可以使用该标签。< foreach >标签有如下属性:


collection:绑定方法参数中的集合,如List,Set,Map或数组对象

item:遍历时的每一个对象

open:语句块开头的字符串

close:语句块结束的字符串

separator:每次遍历之间间隔的字符串

微信图片_20230111212107.png

mapper.xml中的代码如下:


微信图片_20230111212102.png

测试及测试结果如下:


微信图片_20230111212050.png



相关文章
|
5月前
|
XML Java 数据库连接
【MyBatis】MyBatis操作数据库(一)
【MyBatis】MyBatis操作数据库(一)
48 1
|
5月前
|
SQL 存储 Java
基于MyBatis的增删改查操作
基于MyBatis的增删改查操作
41 1
|
2月前
|
SQL XML Java
mybatis复习02,简单的增删改查,@Param注解多个参数,resultType与resultMap的区别,#{}预编译参数
文章介绍了MyBatis的简单增删改查操作,包括创建数据表、实体类、配置文件、Mapper接口及其XML文件,并解释了`#{}`预编译参数和`@Param`注解的使用。同时,还涵盖了resultType与resultMap的区别,并提供了完整的代码实例和测试用例。
mybatis复习02,简单的增删改查,@Param注解多个参数,resultType与resultMap的区别,#{}预编译参数
|
2月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
44 1
|
4月前
|
Java 数据库连接 数据库
mybatis plus 中增删改查及Wrapper的使用
mybatis plus 中增删改查及Wrapper的使用
189 3
|
5月前
|
缓存 Java 数据库连接
我们后端程序员不是操作MyBatis的CRUD Boy
大家好,我是南哥。一个对Java程序员进阶成长颇有研究的人,今天我们接着新的一篇Java进阶指南。为啥都戏称后端是CRUD Boy?难道就因为天天怼着数据库CRUD吗?要我说,是这个岗位的位置要的就是你CRUD,你不得不CRUD。哪有公司天天能给你搭建高并发、高可用、大数据框架的活呢,一条业务线总要成长吧,慢慢成熟了就要装修工来缝缝补补、美化美化,也就是CRUD的活。不能妄自菲薄CRUD Boy,我们是后端工程师。今天来指南下操作数据库之MyBatis框架。
120 3
我们后端程序员不是操作MyBatis的CRUD Boy
|
3月前
|
druid Java 数据库连接
SpringBoot项目整合MybatisPlus持久层框架+Druid数据库连接池,以及实现增删改查功能
SpringBoot项目整合MybatisPlus和Druid数据库连接池,实现基本的增删改查功能。
310 0
|
4月前
|
SQL 缓存 Java
使用MyBatis优化Java持久层操作
使用MyBatis优化Java持久层操作
|
5月前
|
SQL Java 数据库连接
2万字实操案例之在Springboot框架下基于注解用Mybatis开发实现基础操作MySQL之预编译SQL主键返回增删改查
2万字实操案例之在Springboot框架下基于注解用Mybatis开发实现基础操作MySQL之预编译SQL主键返回增删改查
66 2
|
4月前
|
SQL 缓存 Java
使用MyBatis优化Java持久层操作
使用MyBatis优化Java持久层操作