动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句.

1. 数据准备

  1. 数据库表:blog
    字段:id,title,author,create_time,views
CREATE TABLE `blog` (
`id` varchar(50) NOT NULL COMMENT '博客id',
`title` varchar(100) NOT NULL COMMENT '博客标题',
`author` varchar(30) NOT NULL COMMENT '博客作者',
`create_time` datetime NOT NULL COMMENT '创建时间',
`views` int(30) NOT NULL COMMENT '浏览量'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
  1. 实体类:Blog

    
    @Data
    public class blog {
     private String id;
     private String title;
     private String author;
     // 数据库中是create_time, 字段名不一致
     private Date createTime;
     private int views;
    }

BlogMapper:

public interface BlogMapper {
}
  1. 配置 db.properties:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8
user=root
pwd=1234
  1. 配置 mybatis-config.xml :
    在Blog有字段 createTime, 在数据库中的存储为 create_time。其字段不一致。因此,在settings里面添加:

    <setting name="mapUnderscoreToCamelCase" value="true"/>

    就允许驼峰命名。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <properties resource="db.properties"/>

    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${user}"/>
                <property name="password" value="${pwd}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
       <mapper resource="com/dao/BlogMapper.xml" />
    </mappers>

</configuration>
  1. 配置BlogMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pojo.Blog">

</mapper>
  1. 在 com.utils包下创建工具类

    
    public class IDutils {
     public static String getId(){
         return UUID.randomUUID().toString().replace("-","") ;
     }
    
    }
    
  2. 插入初始数据
    编写接口:
    int addBlog(Blog blog);

sql配置文件:

<mapper namespace="com.dao.BlogMapper">
    <insert id="addBlog" parameterType="com.pojo.Blog" >
        insert into blog(id , title, author, create_time, views)
            values (#{id} , #{title}, #{author}, #{createTime}, #{views})
    </insert>
</mapper>

Test:

    @Test
    public void testAddBlog(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);

        Blog blog = new Blog();
        blog.setId(IDutils.getId());
        blog.setCreateTime(new Date());
        blog.setAuthor("张三");
        blog.setTitle("气态之说");
        blog.setViews(455);

        blogMapper.addBlog(blog);
        sqlSession.close();

    }

2. 语句

if

条件判断

根据作者名字和博客名字来查询博客!如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询

  1. 在 BlogMapper中编写接口
//需求1 : 查询博客
List<Blog> queryBlogIf(Map map);
  1. 在BlogMapper.xml 编写SQL语句:
    <!--需求1:
        根据作者名字和博客名字来查询博客!
        如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
        select * from blog where title = #{title} and author = #{author}
    -->
    <select id="queryBlogIf" parameterType="map" resultType="com.pojo.Blog">
        select * from blog
        where 1 = 1
        <if test="title != null">
          title = #{title}
        </if>

        <if test="author != null">
            and author = #{author}
        </if>
    </select>

<if test=""> </if> 判断添加是否满足,满足的话,就自动拼接SQL语句。

Test:

    @Test
    public void testQueryBlogIf(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        Map<String,String> map = new HashMap<String,String>();
        map.put("author","侯杰");
        map.put("title","软件设计模式");
        List<Blog> blogList = blogMapper.queryBlogIf(map);
        for (Blog blog : blogList) {
            System.out.println(blog);
        }

    }

注意:

  1. 在上述where语句后面添加了 “1 = 1”, 如果在<if>不满足的时候,“1 = 1” 能保证 SQL语句的正确性。
  2. 如果去掉“1 = 1” 之后,怎么解决上述问题?,我们接下来可以使用 where 语句。

where

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

  1. 在 BlogMapper中编写接口
//需求1 : 查询博客
List<Blog> queryBlogWhere(Map map);
  1. 在BlogMapper.xml 编写SQL语句:
    <!--需求1:
        根据作者名字和博客名字来查询博客!
        如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
        select * from blog where title = #{title} and author = #{author}
    -->
    <select id="queryWhere" parameterType="map" resultType="com.pojo.Blog">
        select * from blog
        <where>
            <if test="title != null">
                title = #{title}
            </if>
            <if test="author != null">
                author = #{author}
            </if>
        </where>
    </select>
  • 原来的 SQL语句的where 不写

Test:

    @Test
    public void testqueryWhere(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        Map<String,String> map = new HashMap<String,String>();
        map.put("author","侯杰");
        List<Blog> blogList = blogMapper.queryBlogWhere(map);
        for (Blog blog : blogList) {
            System.out.println(blog);
        }
    }

choose、when、otherwise

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

  1. 在 BlogMapper中编写接口
//需求1 : 查询博客
List<Blog> queryBlogChoose(Map map);
  1. 在BlogMapper.xml 编写SQL语句:
    <select id="queryBlogChoose" parameterType="map" resultType="com.pojo.Blog">
        select * from blog
        <where>
            <choose>
                <when test="title != null">
                    title = #{title}
                </when>
                <when test="author !=null">
                    and author = #{author}
                </when>
                <otherwise>
                    and views > #{view}
                </otherwise>
            </choose>
        </where>
    </select>

Test:

    @Test
    public void testqueryBlogChoose(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        Map<String,String> map = new HashMap<String, String>();
//        map.put("title","软件设计模式");
//        map.put("author","侯杰");
        map.put("view","500");

        List<Blog> blogList = blogMapper.queryBlogChoose(map);
        for (Blog blog : blogList) {
            System.out.println(blog);
        }
    }
  • choose、when、otherwise的搭配等价于java中的switch、case;
  • choose下面的when只会有一个被选择出来(相当于每一个 when后面由一个break)

set

  • set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。(和where中的带有同意的道理)。
  • 原生的SQL语句中的set 用 <set> 标签替代。
  1. 在 BlogMapper中编写接口
    //更新博客
    int updateBlog(Map map);
  1. 在BlogMapper.xml 编写SQL语句:
    <!-- 当 if 中的语句和 前面的sql拼接的时候,<set>标签会
        自动的将“,”去除,从而保证正确的sql语法
    -->
  <update id="updateBlog" parameterType="map" >
        update blog
        <set>
            <if test="title != null">
                , title = #{title}
            </if>
            <if test="author != null">
                ,author = #{author}
            </if>
        </set>
        where id = #{id}
    </update>

trim

foreach

有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

把前面中案例中的片段提取出来(用 标签 <sql>来表示):

    <sql id="ifVer">
        <if test="title != null">
            , title = #{title}
        </if>
        <if test="author != null">
            ,author = #{author}
        </if>
    </sql>
    

引用该片段用标签:
<include refid="">

例如:

    <update id="updateBlog" parameterType="map" >
        update blog
        <set>
            <include refid="ifVer" />
        </set>
        where id = #{id}
    </update>

注意事项:

  • 最好基于单表sql片段,多表的复杂性较高
  • 不要把 where等标签放到片段中去

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

1、编写接口

    //查询,根据 Foreach
    List<Blog> queryBlogForeach(Map map);
  1. 在BlogMapper中编写SQL语句:
    <!--
       collection:指定输入对象中的集合属性
       item:每次遍历生成的对象
       open:开始遍历时的拼接字符串
       close:结束时拼接的字符串
       separator:遍历对象之间需要拼接的字符串
    -->
    <!--
        map里传递了一个集合:nameList
    -->

   <!-- select * from blog where ( name = "x1" or name = "x2" or name = "x3")-->
    <select id="queryBlogForeach" parameterType="map" resultType="com.pojo.Blog">
        select * from blog
        <where>
            <foreach collection="nameList" item="name_item" open="(" separator="or" close=")">
                author = #{name_item}
            </foreach>
        </where>

    </select>

Test:

 @Test
    public void testqueryBlogForeach(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);

        HashMap<String,List<String>> hashMap = new HashMap<String,List<String>>();

        List<String> nameList = new ArrayList<String>();
        nameList.add("侯杰");
        nameList.add("李二");
        hashMap.put("nameList", nameList);

        List<Blog> listBlog = blogMapper.queryBlogForeach(hashMap);
        for (Blog blog : listBlog) {
            System.out.println(blog);
        }

        sqlSession.close();
    }


}

phang
1 声望3 粉丝

引用和评论

0 条评论