MyBatis学习笔记(四)——MyBatis动态SQL和代码生成器

前言

动态SQL其实也是MyBatis强大的特性之一,在使用原生JDBC的时候,偶尔的一个符号使用不正确,就会出现问题,MyBatis动态SQL的出现,尽量帮我们规避了这些问题。同时为了规避每次下Mapper.xml的繁琐,MyBatis提供了MBG代码生成器。本篇博客就对这两个问题做个总结。

动态SQL

动态SQL其实就是学习几个标签,但是需要与普通的SQL语句结合起来进行考虑。

先还是贴出基本的类型映射

    
        
        
        
        
        
        
        
    

if标签

if标签可以用于where,update,insert中,其实主要作用就是用于判断,这个好像就是废话,但是还是看实例来的实在

1、where中使用if

现有一个需求——根据用户输入的条件去检索用户信息,如果只输入用户名,则根据用户名进行模糊查询;如果输入邮箱,则根据邮箱完全匹配;如果同时输入邮箱和用户名则同时使用这两个条件进行查询
如果没有动态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标签并不会帮我们手动的拼接这两个关键字

2、update中使用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}可以避免一些异常情况。

3、insert中使用if

这个相对而言就比较简单了,直接上实例吧,

    
        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判断 

choose标签

虽然有了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,如果两个条件都不满足就不会出现异常。

where、set、trim标签

其实在上面的描述过程中,主要提及了一些异常场景的使用,为了规避这些异常场景,使用了一些逻辑去弥补,其实mybatis已经为我们做了很多这方面的工作了。

where标签

还记得第一个if实例中,我们为了规避没有查询条件的时候,加入了1=1这种丑陋的代码,其实有了where标签之后,整个where部分也会动态化起来,如果没有查询条件的时候,就没有where子句。

    
    

set标签

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}避免相关异常情况。

trim

where和set标签底层其实都是通过trim实现的,但是针对trim的使用暂时没有较好的实例,后面会补上。

foreach标签

foreach的使用主要分为两大类,1、SQL中有时候会使用in进行批量查询,foreach可以替代in关键字。2、foreach同时还可以遍历相关集合。

1、foreach实现in集合

有时候批量查询会用到in关键字,前面没有针对in进行梳理,因为简单的in查询会出现SQL注入攻击,现在用foreach会避免注入攻击。

    
    

 foreach标签中有多个属性,其中collection是必填的,表示遍历的集合,这个一般是传入的集合参数名称,item为每个元素起的别名,index是下标,对应的mapper接口中如下:

public List selectByIdList(@Param("ids") Long[] ids);

2、foreach实现批量插入 

    
    
        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同时还设置了返回自增主键。

3、foreach实现动态update

    
    
        update sys_user
        set
        
            ${key} = #{val}
        
        where id = #{id}
    

当参数是map的时候,遍历的index对应的就不是索引值了,而是map中的key

对应的Mapper接口的实现

    public int updateUser(Map userValues);

说明:这里尝试了一下加入@params注解,结果失败了,后面需要重新尝试。

bind

bind只是在使用OGNL的时候,可以用bind创建一个变量而已,这个没有多少可以说的。

MyBatis代码生成器

这里直接上代码生成器的实例,关于配置的详细介绍移步后面的博客。后面会补上传送门。

1、引入该插件的maven依赖


        
            
                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}
                    
                
            
        
    

在上述中指定了配置文件的存放地址和文件名称。 

2、在resources目录下建立配置文件

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文件 





    
    
    
    
    

    
    
    
        
        
        
        
        
        
        

        
        
        
        


        

        

        
        
            
             
            
        

        
        
        
        
            
            
        

        
        
            
            
        
        
        
            
        
        
        
            
        
        
        
            
            
        

3、mvn mybatis-generator:generate

在根目录下执行上述命令即可完成代码的自动生成。

运行成功之后,会出现如下结果,我的实例是之前运行过的,运行该命令之后,会复写相关文件。

MyBatis学习笔记(四)——MyBatis动态SQL和代码生成器_第1张图片

总结

针对动态SQL和MBG插件的使用做了一个总结,还有相关需要补充的地方,后面会继续。

你可能感兴趣的:(#MyBatis)