1.增加操作
1.1 添加用户并返回受影响的行数
1、 在mapper包下(interface)添加方法声明.
2、在xml实现添加业务
3、 单元测试
测试结果:
1.2 添加用户并返回自增ID
1、添加方法声明
2、在xml实现添加业务
useGeneratedKeys:这会令MyBatis使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键(比如:像MySQL和SQL Server这样的关系型数据库管理系统的自动递增字段),默认值:false。
keyColumn:设置生成键值在表中的列名,在某些数据库(像PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。
keyPropety:指定能够唯一识别对象的属性,MyBatis会使用getGeneratedKeys的返回值或insert语句中的selectKey子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性的名称。
3.单元测试
注解@Transactional表示该事务在测试完成后会自动回滚,这也是单元测试的优点,不会污染数据库。
测试结果:
2.删除操作
1、在mapper(interface)里面添加删除的代码声明
注解@Param中的参数需要与xml中的参数对应。
2.在xml中添加< delete >标签和删除的sql
3.单元测试
测试结果:
3.修改操作
1、在mapper(interface)里面添加修改的代码声明
2、在xml中添加< update >标签和具体要执行的SQL
3.单元测试
测试结果:
4.查找操作
4.1 单表查询
4.1.1 参数占位符#{}和${}
#{}:预编译处理
${}:字符直接替换
预编译处理是指:MyBatis在处理#{}时,会将SQL中的#{}替换为?号,使用PreparedStatement的set方法来赋值。
直接替换是指:MyBatis在处理$ {}时,就直接把${}替换成变量的值。
下边通过几个例子来具体了解一下两者的差别:
针对int类型的参数进行查询
使用#{},可以在测试结果中发现,就是把#{}替换成了?占位符,进行预编译处理。
使用${},可以在测试结果中发现,就直接把 ${}替换成变量的值。
但是针对int类型的参数两种占位符都完成了查询,下边我们来看
针对String类型的参数进行查询
使用#{}参数占位符
使用${}参数占位符
发现在使用${}占位符去进行查询时,会发生报错,这是因为通过#{}占位符去进行查询的时候,默认加上了单引号,拼装的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命令,所以执行就会报错。
就像下边这个例子,会有价格从低到高或者从高到低的排序,如果想要实现这样的效果,就需要使用到${}占位符
代码示例:
测试:
4.1.3 SQL注入问题
下边通过一个登录的案例来引入SQL注入的问题:
我们可以发现,当我输入的密码为' 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中登录的例子也就不适用了,所以其更适用于用#{}来解决登录的问题。
可以发现用#{}参数占位符去搜索时,查询不到结果,也就解决了该安全隐患。
4.1.4 like模糊查询
这是一个特殊的查询,如果使用#{}会报错,但使用${}在业务层的值又不能穷举,就需要通过SQL中的concat函数,将%与模糊字符合并起来,如下所示。
4.2 多表查询
如果是增、删、改操作,返回受影响的行数,那么在mapper.xml中是可以不设置返回的类型的,如下图所示:
但即使如果是最简单的查询操作,也需要设置返回类型,否则就会报错。也就是说对于< select >查询标签来说,至少需要两个属性:
id属性:用于标识实现接口中的那个方法
结果映射属性:结果映射有两种实现标签;< resultMap >和< resultType >。
4.2.1 返回类型:resultType
绝大多数查询场景可以使用resultType进行返回,如下代码所示:
其优点是使用方便,直接定义到某个实体类即可。
4.2.2 返回字典映射:resultMap
resultMap使用场景:
字段名称和程序中的属性名不同的情况,可以使用resultMap配置映射;
一对一和一对多关系可以使用resultMap映射并查数据
字段名和属性名不同的情况:
mapper.xml中的代码:
单元测试代码:
单元测试结果:
查询不到name属性,这时候就需要用到resultMap了,resultMap的使用如下:
查询成功:
4.2.3 多表查询
在多表查询时,如果使用resultType标签,在一个类中包含了另一个对象,是查询不出来被包含的对象的,比如以下实体类:一篇文章对应一个作者,文章实体类中包含对象实体。
mapper.xml代码如下:
测试代码如下:
测试结果:
此时,我们就需要使用特殊的手段来实现联表查询了。
一对一的表映射
一对一映射要使用< association >标签,具体实现如下(一篇文章只对应一个作者):
以上使用< association >标签,表示一对一的结果映射:
property属性:指定Article中对应的属性,即用户。
resultMap属性:指定关联的结果集映射,将基于该映射配置来组织用户数据。
columnPrefix属性:如遇多表中有相同字段名时,该属性作为区分不同表中相同字段的前缀。
映射的mapper.xml文件如下:
测试代码如下:
测试结果:
一对多的表映射
一对多需要使用< collection >标签,用法和< association >相同,如下所示:(一个用户对应多篇文章)
测试结果:
5.动态SQL
5.1 < if >标签
我们在进行注册功能时,可能涉及到必填字段和非必填字段两类字段,那如果在添加用户的时候,有不确定的字段传入,程序此时就应该使用动态标签< if >来判断了,该标签的主要作用是判断一个参数是否有值,如果没值,那么会隐藏if中的SQL,如下的photo字段。
拼装的SQL就会根据是否传入了photo参数来确定是否增添photo字段。
5.2 < trim >标签
之前的插入用户功能,只有一个photo字段可能是选填项,如果所有字段都是非必填项,就考虑使用< trim >标签结合< if >标签,对多个字段都采取动态生成的方式。最主要的作用就是:去除SQL语句前后多余的某个字符
prefix:表示整个语句块,以prefix的值作为前缀
suffix:表示整个语句块,以suffix的值作为后缀
prefixOverrides:表示整个语句块要去除掉的前缀
suffixOverriders:表示整个语句块要去除的后缀
调整UserMapper.xml的插入语句为:
测试结果:
5.3 < where >标签
该标签的主要作用是:
实现查询中的where SQL替换,如果没有任何的查询条件,那么它可以隐藏查询查询中的where SQL,但如果存在查询条件,那么就会生成where的SQL查询;并且使用where标签可以自动的去除最前面的一个and字符
mapper.xml中的代码如下:
测试结果:
以上< where >标签也可以使用< trim prefix="where" prefixOverrides="and" >替换。
5.4 < set >标签
该标签的主要作用是:
进行修改操作时,配合if来处理非必传参数,它的特点是会自动去除最后一个英文逗号。
mapper中的代码如下
mapper.xml中的代码如下:
测试及测试结果如下:
以上< set >标签也可以使用< trim prefix="set" suffixOverrides="," >替换
5.5 < foreach >标签
对集合进行遍历时可以使用该标签。< foreach >标签有如下属性:
collection:绑定方法参数中的集合,如List,Set,Map或数组对象
item:遍历时的每一个对象
open:语句块开头的字符串
close:语句块结束的字符串
separator:每次遍历之间间隔的字符串
mapper.xml中的代码如下:
测试及测试结果如下: