动态SQL其实也是MyBatis强大的特性之一,在使用原生JDBC的时候,偶尔的一个符号使用不正确,就会出现问题,MyBatis动态SQL的出现,尽量帮我们规避了这些问题。同时为了规避每次下Mapper.xml的繁琐,MyBatis提供了MBG代码生成器。本篇博客就对这两个问题做个总结。
动态SQL其实就是学习几个标签,但是需要与普通的SQL语句结合起来进行考虑。
先还是贴出基本的类型映射
if标签可以用于where,update,insert中,其实主要作用就是用于判断,这个好像就是废话,但是还是看实例来的实在
现有一个需求——根据用户输入的条件去检索用户信息,如果只输入用户名,则根据用户名进行模糊查询;如果输入邮箱,则根据邮箱完全匹配;如果同时输入邮箱和用户名则同时使用这两个条件进行查询。
如果没有动态SQL,则相关查询语句会如下书写:
其实问题很明显,当用户输入了用户名,但是没有输入userEmail,这个时候就会有user_email=null这样一个异常,这肯定是不允许的,所以我们需要SQL的动态化,如果用户没有输入user_email,则就不用出现user_email = ‘userEmail’的查询条件。
这个时候If标签就可以在where中派上用场了。
一般格式:
于是可以将上述SQL语句变成下面这样:
注意上面加了一个where 1=1,加入这个的目的就是为了防止没有输入参数的时候,SQL语句会直接以where结尾(select * from sys_user where)加上这个1=1是为了避免这种情况,后面的where标签就是为了替代这种恶心的写法。需要注意if中的and或者or,if标签并不会帮我们手动的拼接这两个关键字。
需求:使用update只更新有变化的字段——即只传入我们想要更新的字段即可,不需要每次更新的时候传递全部字段,如果做到SQL的动态定制
update sys_user
set
user_name = #{userName},
user_password = #{userPassword},
user_email = #{userEmail},
user_info = #{userInfo},
head_img = #{headImg},
create_time = #{createTime,jdbcType=TIMESTAMP},
id = #{id}
where id = #{id}
上面直接给出了满足该需求的动态SQL语句,但是这里需要结合相关业务,来分析一下这个SQL语句的正确性。主要有两个需要注意的地方,1.每个if标签中的SQL语句都有逗号,2.where关键字前面的id = #{id}这个条件。
1、如果我们没有传递任何条件,最终的SQL语句对应如下
update sys_user set where id = #{id} 这个SQL明显错误,所以我们需要有 id = #{id}避免这种情况,如果没有传递条件则SQL语句为:update sys_user set id = #{id} where id = #{id}
2、如果只有一个条件,对应的SQL语句如下
在没有id=#{id}的时候,update sys_user set user_name = #{user_name}, where id = #{id},where前有个无聊的逗号,这个SQL也是错误的。
综上id = #{id}可以避免一些异常情况。
这个相对而言就比较简单了,直接上实例吧,
insert into
sys_user(
user_name,user_password,
user_email,
user_info,head_img,create_time)
values (#{userName},#{userPassword},
#{userEmail},
#{userInfo},#{headImg,jdbcType = BLOB},
#{createTime,jdbcType=TIMESTAMP}
)
只是需要注意,在列的部分增加了if判断,在values中也需要增加相关的if判断 。
虽然有了if标签,但是暂时没法进行if...else判断啊 choose就是干这个的,choose标签中至少有一个when,有0个或者1个otherwise。
需求:在已有的sys_user表中,当参数id有值的时候优先使用id查询,当id没有值的时候就去判断用户名是否有值,如果有就用用户名查询,如果也没有,就查询无结果,上述逻辑用伪码表示如下
if(id is exists){
if(userName is exist){
return findUserByIdAndUserName(id,userName);
}
else{
return findUserBuIdAndUserName(id);
}
}else{
if(userName is exist){
return findUserByIdAndUserName(userName);
}else{
return null;
}
}
上述伪代码有点臃肿,但是也算是将文字逻辑表述清楚了,这个也是为了与后面的choose标签的动态SQL语句对应起来 。
如果上述动态SQL如果没有加入1=2,在条件不满足的时候,就会查出所有的用户数据,但是函数返回结果只会返回一个结果,如果返回多个会出现异常,为了规避这种情况,就加入1=2,如果两个条件都不满足就不会出现异常。
其实在上面的描述过程中,主要提及了一些异常场景的使用,为了规避这些异常场景,使用了一些逻辑去弥补,其实mybatis已经为我们做了很多这方面的工作了。
还记得第一个if实例中,我们为了规避没有查询条件的时候,加入了1=1这种丑陋的代码,其实有了where标签之后,整个where部分也会动态化起来,如果没有查询条件的时候,就没有where子句。
set存在同样的问题,但是set标签貌似并没有完全达到where标签的级别
update sys_user
user_name = #{userName},
user_password = #{userPassword},
user_email = #{userEmail},
user_info = #{userInfo},
head_img = #{headImg,jdbcType=BLOB},
create_time = #{createTime,jdbcType=TIMESTAMP},
id = #{id},
where id = #{id}
上述引入了set标签,但是只解决了逗号问题,即,不会出现update sys_user set user_name = #{userName} , where id = #{id};的情况了,set标签会自动将逗号删除,但是 update sys_user set where id = #{id} 的毛病依旧,所以在where之前还是需要加入id = #{id}避免相关异常情况。
where和set标签底层其实都是通过trim实现的,但是针对trim的使用暂时没有较好的实例,后面会补上。
foreach的使用主要分为两大类,1、SQL中有时候会使用in进行批量查询,foreach可以替代in关键字。2、foreach同时还可以遍历相关集合。
有时候批量查询会用到in关键字,前面没有针对in进行梳理,因为简单的in查询会出现SQL注入攻击,现在用foreach会避免注入攻击。
foreach标签中有多个属性,其中collection是必填的,表示遍历的集合,这个一般是传入的集合参数名称,item为每个元素起的别名,index是下标,对应的mapper接口中如下:
public List selectByIdList(@Param("ids") Long[] ids);
insert into sys_user (user_name,user_password,user_email,user_info,head_img,create_time)
values
(
#{user.userName},#{user.userPassword},#{user.userEmail},
#{user.userInfo},#{user.headImg,jdbcType=BLOB},
#{user.createTime,jdbcType=TIMESTAMP})
具体的Mapper接口
public int insertUsers(@Param("users") List users);
collections指定的值与param指定的属性值名称一样。同时指定相关属性的时候,需要指定item所指定的名称。上述insert同时还设置了返回自增主键。
update sys_user
set
${key} = #{val}
where id = #{id}
当参数是map的时候,遍历的index对应的就不是索引值了,而是map中的key
对应的Mapper接口的实现
public int updateUser(Map userValues);
说明:这里尝试了一下加入@params注解,结果失败了,后面需要重新尝试。
bind只是在使用OGNL的时候,可以用bind创建一个变量而已,这个没有多少可以说的。
这里直接上代码生成器的实例,关于配置的详细介绍移步后面的博客。后面会补上传送门。
org.springframework.boot
spring-boot-maven-plugin
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.2
${basedir}/src/main/resources/mybatis-generator.xml
true
true
mysql
mysql-connector-java
${mysql.version}
在上述中指定了配置文件的存放地址和文件名称。
1、建立mybatisGeneratorinit.properties配置文件,这个文件会被mybatis-generator.xml引用
#Mybatis Generator configuration
#dao类和实体类的位置
project=src/main/java
#mapper文件的位置
resources=src/main/resources/mapper
#根据数据库中的表生成对应的pojo类、dao、mapper
jdbc_driver=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/mybatischapter02?serverTimezone=GMT
jdbc_user=root
jdbc_password=root
下一个配置文件会引用这个访问信息。
2、建立mybatis-generator.xml文件
在根目录下执行上述命令即可完成代码的自动生成。
运行成功之后,会出现如下结果,我的实例是之前运行过的,运行该命令之后,会复写相关文件。
针对动态SQL和MBG插件的使用做了一个总结,还有相关需要补充的地方,后面会继续。