mybatis动态SQL语句

1. mybatis 与 JDBC对比

1.1、传统JDBC动态SQL

在学习mybatis动态SQL语句之前,先来回忆一下JDBC的SQL操作。看看传统的JDBC操作是多么的难受,手动控制一些参数条件。

StringBuffer sql = new StringBuffer();
ArrayList<Object> obj = new ArrayList<>();
sql.append("select * from smbms_provider");
boolean f = false;
if(proCode != null && proCode != ""){			
    sql.append(" where proCode like ?");
    obj.add("%" + proCode + "%");
    f = true;
}
if(proName != null && proName != ""){
    if(f){
        sql.append(" and proName like ?");
    }
    else{
        sql.append(" where proName like ?");
    }
    obj.add("%" + proName +"%");
}
  1. 分析SQL语句,这个SQL语句可能传入两个参数proCode 和 proName两个参数,注意这里是可能,不一定两个都有也不一定两个都没有。

  2. 如果第一个参数proCode有,首先得拼接一个where字段,再来拼接条件。

  3. 第二个参数就麻烦了,如果第一个参数proCode有,第二个参数存在就拼接 and 再拼接条件。如果第一个参数proCode没有,那么就只有一个条件需要拼接 where 再拼接条件。因为不可能出现这种where and错误SQL语句啊!

  4. 如果后面还有第三、第四、第五…条件,得一个个接着来。接着判断前面是否有条件?此处拼接where 还是 and?

这里就能看到传统JDBC的短板在哪了吧,是不是感觉灵活度不高?拼接SQL语句有没有像做OJ题控制输出格式,首尾不能有空格,中间有空格…反正我是做吐了,对格式控制不能说了解只能说非常了解!


1.2、mybatis动态SQL

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL可以彻底摆脱这种痛苦。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

因此mybatis提供了四大类标签解决动态SQL语句问题,mybatis又一个强大的核心特性。



2. 搭建基本环境

  1. mybatis-config.xml配置文件,基本部分略去。

    <settings>
        <!-- 开启日志 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    
        <!-- 将经典的SQL字段映射为Java驼峰命名变量-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    
    <typeAliases>
        <typeAlias type="com.pojo.Blog" alias="Blog"/>
    </typeAliases>
    
    <mappers>
        <mapper class="com.dao.BlogMapper"/>
    </mappers>
    
  2. Blog实体类

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Blog {
        private String id;              //id
        private String title;           //标题
        private String author;          //作者
        private Date createTime;        //创建时间
        private int views;              //浏览量
    }
    
  3. BlogMapper接口

    public interface BlogMapper {
    
        List<Blog> getBlogByIf(Map map);
    
    	List<Blog> getBlogByChoose(Map map);
    	
    	int updateBlog(Map map);
    
    	List<Blog> getBlogByForEach(@Param("arraylist") List list);
    }
    


3. if 标签

首先解决一下类似于上述JDBC代码的,痛苦SQL拼接问题。其实上述where可以单独处理,多加一个永远成立的第一个条件where 1 = 1。无论你后面是否有条件都不需要管where字段了。只需要无脑and + 条件即可。

<select id="getBlogByIf" parameterType="map" resultType="Blog">
    select *from blog where 1 = 1
    
    <if test="views != null">
        and views > #{views}
    </if>

    <if test="author != null">
        and author = #{author}
    </if>
</select>
@Test
public void test_if(){
    SqlSession session = mybatisUtil.getSqlSession(true);
    BlogMapper mapper = session.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    map.put("author","张三");			//参数1		
    map.put("views",5000);				//参数2			
    List<Blog> blogs = mapper.getBlogByIf(map);
    for (Blog blog : blogs) {
        System.out.println(blog.toString());
    }
    session.close();
}
  1. 一个参数都不传的情况,此时数据库中所有的数据都被查出来了(共10条)
    在这里插入图片描述

  2. 两个参数任意传一个
    在这里插入图片描述

  3. 传两个参数
    在这里插入图片描述



4. trim(where、set)标签

4.1、where标签

现在来解决一下where 和 and冲突的问题,上面我们使用的是where 1 = 1加一个永远成立的条件来屏蔽where关键词,之后加条件不需要考虑所加的条件是否是第一个条件。从而解决where 和 and 的冲突问题,现在mybatis提供了where标签,可以将我们的where字段释放出来!where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

<select id="getBlogByIf" parameterType="map" resultType="Blog">
    select *from blog
    <where>
        <if test="views != null">
            and views > #{views}
        </if>

        <if test="author != null">
            and author = #{author}
        </if>
    </where>
</select>
4.2、set标签

set标签与where标签一样,它的诞生也是为了解决SQL语句语法错误问题,update语句在修改字段时,不知道具体需要修改几个字段,修改多个字段需要用逗号隔开?还是回到上面的问题,需要对逗号分隔符进行单独特殊处理!为了解决这种问题mybatis又将set字段释放出来,不需要手动处理" ,"问题。

<update id="updateBlog" parameterType="map">
    update blog
    <set>
        <if test="title != null"> title = #{title}, </if>
        <if test="views != null"> views = #{views}, </if>
    </set>
    <where>
        <if test="id != null"> id = #{id} </if>
    </where>
</update>

在这里插入图片描述

4.3、trim标签

trim标签是用来定制where、set…标签的,不定制的情况下where会处理与and | or 引起的语法错误问题,set也只处理 与“,”引起的语法错误问题,当然也可以手动定制!

<trim prefix="WHERE" prefixOverrides="AND |OR ">		等价普通where
  ...
</trim>

<trim prefix="SET" suffixOverrides=",">					等价普通set
  ...
</trim>


5. choose(when、otherwise)标签

choose、when、otherwise有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

按照when的顺序匹配,一旦有一个成功就执行。之后所有的when 、otherwise都不会在执行;如果一个都不匹配就走otherwise(otherwise可以没有)。

<select id="getBlogByChoose" parameterType="map" resultType="Blog">
    select *from blog
    <where>
        <choose>
            <when test="title != null">
                and title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>
            <otherwise>
                and views > #{views}
            </otherwise>
        </choose>
    </where>
</select>
@Test
public void test_choose(){
    SqlSession session = mybatisUtil.getSqlSession(true);
    BlogMapper mapper = session.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    map.put("title","Mybatis");
    map.put("author","李四");
    map.put("views",5000);
    List<Blog> blogs = mapper.getBlogByChoose(map);
    for (Blog blog : blogs) {
        System.out.println(blog.toString());
    }
    session.close();
}

在这里插入图片描述



6. SQL片段标签

mybatis的宗旨就是能简化就简化,将程序员从Dao层释放出来。因此mybatis也提供了SQL片段这个标签,用于抽取一些公共的代码,致力于能够达到复用的地步。在需要的时候通过include标签引入即可,像极了JSTL。

<sql id="views-author">
    <if test="views != null">
        and views > #{views}
    </if>

    <if test="author != null">
        and author = #{author}
    </if>
</sql>
<select id="getBlogByIf" parameterType="map" resultType="Blog">
    select *from blog
    <where>
       <include refid="views-author"/>
    </where>
</select>

@Test
public void test_sql(){
    SqlSession session = mybatisUtil.getSqlSession(true);
    BlogMapper mapper = session.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    map.put("author","张三");
    map.put("views",5000);
    List<Blog> blogs = mapper.getBlogByIf(map);
    for (Blog blog : blogs) {
        System.out.println(blog.toString());
    }
    session.close();
}

在这里插入图片描述

  • 抽取公共代码片段的时候尽量抽取独立性较高的片段,不要加入< where >、< set >等等标签。尽量只有一些 where 子条件语句、< if >之类的东西。

  • 最好基于单表来定义SQL片段,不要多表抽取,那么将失去更多的复用性。



7. foreach标签

  1. foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!

  2. 可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

<select id="getBlogByForEach" parameterType="arraylist" resultType="Blog">
    select *from blog where author in
    <foreach collection="arraylist" index="index" item="item"
             open="(" separator="," close=")">
        #{item}
    </foreach>
</select>


@Test
public void test_foreach(){
    SqlSession session = mybatisUtil.getSqlSession(true);
    BlogMapper mapper = session.getMapper(BlogMapper.class);
    List list = new ArrayList();
    list.add("张三");
    list.add("赵四");
    List<Blog> blogs = mapper.getBlogByForEach(list);			//参数@Param("arraylist") List list
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    session.close();
}

在这里插入图片描述



8. 总结

  1. 动态SQL就是指根据不同的条件生成不同的SQL语句

  2. 动态SQL本质还是SQL语句 , 只是我们可以在SQL层面去执行一个逻辑代码

  3. 动态SQL就是拼接SQL语句,只要按照SQL的格式,保证SQL的正确性,去组合就行了

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值