09 动态sql

1 if标签

1.1 引入

比如下面的接口,我们期望根据查询条件动态查询用户信息

/****
 * 根据条件查询用户
 * @param tbUser
 * @return
 */
List<TbUser> selectUser(TbUser tbUser);
 <select id="selectUser" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
     select
         *
     from
         tb_user
     where
         `id` = #{id}
         and `username` = #{username}
         and `phone` = #{phone}
         and `password` = #{password}

 </select>

测试:

 TbUserMapper tbUserMapper;

 @Before
 public void getMapper() throws IOException {
     // 加载全局配置文件
     InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
     // 构建sqlSessionFactory
     SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
     // 获取sqlSession
     SqlSession sqlSession = sqlSessionFactory.openSession();
     // 生成Mapper接口的代理对象
     tbUserMapper = sqlSession.getMapper(TbUserMapper.class);
 }

 @Test
 public void test01() {
     TbUser user = new TbUser();
     user.setId(1L);
     user.setUsername("kobe");
     tbUserMapper.selectUser(user);
 }

查询结果是空,但是数据库查询在id为1且username是kobe的数据,为何呢,查看日志输出的sql

select * from tb_user where `id` = 1 and `username` = "kobe" and `phone` = null and `password` = null 

这条sql其实不是我们期望的sql,我们期望的sql,应该是

select * from tb_user where `id` = 1 and `username` = "kobe"

由于没有传phone和password,就不要给我们赋值为null,这样就导致数据没有查出来

更进一步来说,就是说希望sql能够根据我们的赋值动态的拼接查询条件

1.2 if标签改造sql映射文件

  • 使用if标签判断是否该字段赋值
 <select id="selectUser" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
     select
     *
     from
     tb_user
     where
     <!-- test:判断表达式(OGNL)
	 	从参数中取值进行判断
	 	遇见特殊符号应该去写转义字符:
	 	&&:
	 -->
     <if test="id != null">
         `id` = #{id}
     </if>
     <if test="username != null">
         and `username` = #{username}
     </if>
     <!-- 
     	还可以执行函数,还可以使用逻辑运算
     	and: 
     	or
	 -->
    <if test="phone != null and phone.trim() != null">
         and `phone` = #{phone}
     </if>
     <if test="password != null">
         and `password` = #{password}
     </if>
 </select>
  • 再次测试发现可以查询处结果,此时sql,没有在拼接phone和password
select * from tb_user where `id` = ? and `username` = ? 

1.3 OGNL

OGNL( Object Graph Navigation Language )对象图导航语言, 这是一种强大的表达式语言,通过它可以非常方便的来操作对象属性。 类似于我们的EL, SpEL等。

  • 访问对象属性: person.name
  • 调用方法: person.getName()
  • 调用静态属性/方法: @java.lang.Math@PI、@java.util.UUID@randomUUID()
  • 调用构造方法: new com.lun.Person(‘admin’).name
  • 运算符: +, -*, /, %
  • 逻辑运算符: in, not in, >, >=, <, <=, ==, !=
    注意: xml中特殊符号如”,>,<等这些都需要使用转义字符

访问集合伪属性:

类型伪属性伪属性对应的 Java 方法
List、 Set、 Mapsize、 isEmptyList/Set/Map.size(),List/Set/Map.isEmpty()
List、 SetiteratorList.iterator()、 Set.iterator()
Mapkeys、 valuesMap.keySet()、 Map.values()
Iteratornext、 hasNextIterator.next()、 Iterator.hasNext()

2 where标签

2.1 问题引入

刚刚的查询,如果是这样的:

@Test
  public void test02() {
      TbUser user = new TbUser();
      // id不赋值
      //user.setId(1L);
      user.setUsername("kobe");
      tbUserMapper.selectUser(user);
  }

发现报错,查看日志的sql

select * from tb_user where and `username` = ? 

显然是sql语法不对,因为id为null,跳过了,导致拼接username的时候,多拼接了一个and

所以解决方式,就是想办法去掉这个and,如果我们在where 条件后面永远跟一个 1=1呢:
给where后面加上1=1,以后的条件都and xxx。

select * from tb_user where 1=1 and `username` = ? 
   <select id="selectUser" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
        select
        *
        from
        tb_user
        where
        <!--这样即使没有id条件,多出的and就和 1=1这个条件 进行拼了-->
         1=1
        <if test="id != null">
            and `id` = #{id}
        </if>
        <if test="username != null">
            and `username` = #{username}
        </if>
        <if test="phone != null and phone.trim() != null">
            and `phone` = #{phone}
        </if>
        <if test="password != null">
            and `password` = #{password}
        </if>
    </select>

2.2 where标签

mybatis推荐使用where标签解决,mybatis使用where标签来将所有的查询条件包括在内。mybatis就会将where标签中拼装的sql,多出来的and或者or去掉

 <select id="selectUser" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
     select
     *
     from
     tb_user
     <where>
         <if test="id != null">
             `id` = #{id}
         </if>
         <if test="username != null">
             and `username` = #{username}
         </if>
         <if test="phone != null and phone.trim() != null">
             and `phone` = #{phone}
         </if>
         <if test="password != null">
             and `password` = #{password}
         </if>
     </where>
 </select>

这样也可以解决问题,但是where只解决前and(or)问题

比如:我们的and可以放到后面写:


 <select id="selectUser2" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
     select
     *
     from
     tb_user
     <where>
         <if test="id != null">
             `id` = #{id} and
         </if>
         <if test="username != null">
             `username` = #{username} and
         </if>
         <if test="phone != null and phone.trim() != null">
             `phone` = #{phone} and
         </if>
         <if test="password != null">
             `password` = #{password}
         </if>
     </where>
 </select>

运行发现,又出现sql语法错误:

// 后面这个and没有去掉
select * from tb_user WHERE `username` = ? and 

所以where只会去掉前面多出来的and或者or,但后面多出来的and或者or则不会去掉

3 trim标签-自定义字符串截取

trim标签体中是整个字符串拼串后的结果。

  • prefix:
    • prefix给拼串后的整个字符串加一个前缀
  • prefixOverrides:
    • 前缀覆盖: 去掉整个字符串前面多余的字符
  • suffix:
    • suffix给拼串后的整个字符串加一个后缀
  • suffixOverrides:
    • 后缀覆盖:去掉整个字符串后面多余的字符

比如使用trim标签后面多出的and或者or where标签不能解决,但是这个trim标签用的很少,做个了解就行

    <select id="selectUser2" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
        select
        *
        from
        tb_user
        <!--前面 整个添加一个前缀 where
        去掉整个字符串后面多余的and
        -->
        <trim prefix="where" suffixOverrides="and">
            <if test="id != null">
                `id` = #{id} and
            </if>
            <if test="username != null">
                `username` = #{username} and
            </if>
            <if test="phone != null and phone.trim() != null">
                `phone` = #{phone} and
            </if>
            <if test="password != null">
                `password` = #{password}
            </if>
        </trim>
    </select>

4 choose标签–分支选择

类似于switch-case

    <select id="selectUser3" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
        select
        *
        from
        tb_user
        <where>
            <choose>
                <!-- 如果用户ID不为空,就是根据用户id查询-->
                <when test="id != null">
                    id=#{id}
                </when>
                <!-- 如果用户ID为空,但是用户名不为空,就是根据用户名模糊查询-->
                <when test="username!=null">
                    username like '$'#{username}'$'
                </when>
                <!-- 如果用户ID和用户名都为空,就是查询id=1  也就是otherwise相当于 switch case 的default分支-->
                <otherwise>
                    id = 1
                </otherwise>
            </choose>
        </where>
    </select>

    @Test
    public void test04() {

        TbUser user = new TbUser();
        // 如果用户ID和用户名都为空,就是查询id=1  也就是otherwise相当于 switch case 的default分支
        // select * from tb_user WHERE id = 1
        tbUserMapper.selectUser3(user);
        // 如果用户ID为空,但是用户名不为空,就是根据用户名模糊查询
        // select * from tb_user WHERE username like '$'?'$'
        user.setUsername("t-mac");
        tbUserMapper.selectUser3(user);
        // 如果用户ID不为空,就是根据用户id查询
        // select * from tb_user WHERE id=?
        user.setId(2L);
        tbUserMapper.selectUser3(user);
    }

5 set和if实现动态更新

<update id="update">
   update
   tb_user
   set
   <if test="username != null">
       username = #{username},
   </if>
   <if test="password != null">
       password = #{password},
   </if>
   <if test="phone != null">
       phone = #{phone}
   </if>
   where id=#{id}
</update>
@Test
public void test05() {
    TbUser user = new TbUser();
    user.setId(1L);
    user.setUsername("kobe");
    tbUserMapper.update(user);
}

测试发现存在和之前查询时候 and一样的问题, username = ?,后面多了一个逗号

update         tb_user                                username = ?,                                                where id=?

如何修改呢?mybatis同样也提供了一个标签, 用于消除这个逗号

<update id="update">
    update
    tb_user
    <set>
        <if test="username != null">
            username = #{username},
        </if>
        <if test="password != null">
            password = #{password},
        </if>
        <if test="phone != null">
            phone = #{phone}
        </if>
    </set>
    where id=#{id}
</update>

6 foreach-遍历集合

  • collection:指定要遍历的集合:
    • list类型的参数会特殊处理封装在map中,map的key就叫list
  • item:将当前遍历出的元素赋值给指定的变量
  • separator:每个元素之间的分隔符
  • open:遍历出所有结果拼接一个开始的字符
  • close:遍历出所有结果拼接一个结束的字符
  • index:索引。遍历list的时候是index就是索引,item就是当前值
    • 遍历map的时候index表示的就是map的key,item就是map的值
  • #{变量名}就能取出变量的值也就是当前遍历出的元素

6.1 批量查询

/****
* 批量根据id查询
* @param ids
* @return
*/
List selectByIds(List<Long> ids);
<select id="selectByIds" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
    select
    *
    from
    tb_user
    where id in
    <!--
         collection:指定要遍历的集合:
         item:将当前遍历出的元素赋值给指定的变量
         separator:每个元素之间的分隔符
         index:索引。遍历list的时候是index就是索引,item就是当前值
         遍历map的时候index表示的就是map的key,item就是map的值

    -->
    <foreach collection="ids" item="item_id" open="(" close=")" separator=",">
        #{item_id}
    </foreach>
</select>

测试

@Test
 public void test06() {
     tbUserMapper.selectByIds(Arrays.asList(1L, 2L, 3L));
 }

日志输出sql:

select * from tb_user where id in ( ? , ? , ? ) 

6.2 批量插入

/****
 * 批量插入
 * @param tbUsers
 * @return
 */
Boolean creates(@Param("tbUsers") List<TbUser> tbUsers);
<!-- 批量保存
Boolean creates(@Param("tbUsers") List<TbUser> tbUsers);
-->
<!--MySQL下批量保存:可以foreach遍历   mysql支持values(),(),()语法-->
<insert id="creates">
   insert into tb_user(username,password,phone,create_time,update_time)
   values
   <foreach collection="tbUsers" item="user" separator=",">
       (#{user.username},#{user.password},#{user.phone},now(),now())
   </foreach>
</insert>

测试

@Test
public void test07() {
    TbUser tbUser = new TbUser();
    tbUser.setUsername("james");
    tbUser.setPassword("123213");
    tbUser.setPhone("13100001001");

    TbUser tbUser1 = new TbUser();
    tbUser1.setUsername("wade");
    tbUser1.setPassword("123213");
    tbUser1.setPhone("13100001001");
    tbUserMapper.creates(Arrays.asList(tbUser, tbUser1));
    sqlSession.commit();
}

7 动态sql-内置参数 _parameter & _databaseId

  • 不只是方法传递过来的参数可以被用来判断,mybatis默认还有两个内置参数:
    • 单个参数:_parameter就是这个参数
    • 多个参数:参数会被封装为一个map;_parameter就是代表这个map
  • _databaseId:如果配置了databaseIdProvider标签。
    • _databaseId就是代表当前数据库的别名
<select id="selectUser" resultType="study.wyy.mybatis.dynamisc.model.TbUser">

	<if test="_databaseId=='mysql'">
		select * from tb_user
		<if test="_parameter!=null">
			where username like #{_parameter.username}
		</if>
	</if>

	<if test="_databaseId=='oracle'">
		select * from tb_user
		<if test="_parameter!=null">
			where username like #{_parameter.username}
		</if>
	</if>
</select>

7 动态sql-sql-抽取可重用的sql片段

抽取可重用的sql片段。方便后面引用:

  1. sql抽取:经常将要查询的列名,或者插入用的列名抽取出来方便引用
  2. include来引用已经抽取的sql:
  3. include还可以自定义一些property,sql标签内部就能使用自定义的属性
    • include-property:取值的正确方式${prop},
    • 不能使用#{},而使用${}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值