程序员

MyBatis中的动态SQL语句

2020-08-09  本文已影响0人  凡哥爱丽姐
    项目配置给上一章的模糊查询一样,并根据上一章内容讲解本节内容,上一章中我们讲解了三种模糊查询都是多条件查询,若我们要查询含‘张’字的所有用户,不指定性别,则会出现什么情况呢?
import com.fan.dao.UserDao;
import com.fan.entity.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

public class Test1 {
    public static void main(String[] args) {
        try {
            Reader resourceAsReader = Resources.getResourceAsReader("mybatis-config.xml");
            SqlSession sqlSession = new SqlSessionFactoryBuilder().build(resourceAsReader).openSession();
            UserDao mapper = sqlSession.getMapper(UserDao.class);
            List<User> users = mapper.findByNameAndSex("张", null);
            for (User user:users) {
                System.out.println(user);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
    测试结果如下图所示:
测试结果
    通过运行结果发现,查询出来的用户列表为空,在MySQL数据库中执行该SQL语句,查询结果确实为空。但根据正常的逻辑思考,在用户没有输入用户性别的情况下,只根据名称进行模糊查询,结果应该是所有name中含“孙”的用户信息。

1、解决方案是使用动态SQL的if元素来实现多条件查询

1.1、修改配置文件UserDaoMapper.xml

<mapper namespace="com.fan.dao.UserDao">
    <select id="findByNameAndSex" resultType="com.fan.entity.User">
         select * from users where
        <if test="uname!=null">
            name like "%"#{uname}"%"
        </if>
        <if test="usex!=null">
            and sex=#{usex}
        </if>
    </select>
</mapper>

1.2、测试类

import com.fan.dao.UserDao;
import com.fan.entity.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

public class Test1 {
    public static void main(String[] args) {
        try {
            Reader resourceAsReader = Resources.getResourceAsReader("mybatis-config.xml");
            SqlSession sqlSession = new SqlSessionFactoryBuilder().build(resourceAsReader).openSession();
            UserDao mapper = sqlSession.getMapper(UserDao.class);
            List<User> users = mapper.findByNameAndSex("张", null);
            for (User user:users) {
                System.out.println(user);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

测试结果如下图所示:

测试结果
    通过运行结果发现,通过动态SQL语句,只根据名称进行模糊查询,结果可以显示所有name中含“孙”的用户信息。

    若现在我们要找出性别为“男”的用户,直接修改上述的测试类,会实现该要求吗?

List<User> users = mapper.findByNameAndSex(null, "男");

测试结果如下图所示:

测试结果
    我们可以发现SQL语句出现了错误,即where子句后面多了一个“and”,那么我们可以通过下述方法去解决该问题

2、解决方案

2.1、方案1

2.1.1、修改配置文件UserDaoMapper.xml中的SQL语句

<mapper namespace="com.fan.dao.UserDao">
    <select id="findByNameAndSex" resultType="com.fan.entity.User">
         select * from users where 1=1
        <if test="uname!=null and uname!=''">
            and name like "%"#{uname}"%"
        </if>
        <if test="usex!=null">
            and sex=#{usex}
        </if>
    </select>
</mapper>

2.1.2、测试类

import com.fan.dao.UserDao;
import com.fan.entity.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

public class Test1 {
    public static void main(String[] args) {
        try {
            Reader resourceAsReader = Resources.getResourceAsReader("mybatis-config.xml");
            SqlSession sqlSession = new SqlSessionFactoryBuilder().build(resourceAsReader).openSession();
            UserDao mapper = sqlSession.getMapper(UserDao.class);
            List<User> users = mapper.findByNameAndSex(null, "男");
            for (User user:users) {
                System.out.println(user);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

测试结果如下图所示: 测试结果

2.2、方案2

2.2.1、修改配置文件UserDaoMapper.xml中的SQL语句

<mapper namespace="com.fan.dao.UserDao">
    <select id="findByNameAndSex" resultType="com.fan.entity.User">
         select * from users
        <where>
            <if test="uname!=null and uname!=''">
                   and name like "%"#{uname}"%"
            </if>
            <if test="usex!=null">
                   and sex=#{usex}
            </if>
        </where>
    </select>
</mapper>

2.2.2、测试类

import com.fan.dao.UserDao;
import com.fan.entity.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

public class Test1 {
    public static void main(String[] args) {
        try {
            Reader resourceAsReader = Resources.getResourceAsReader("mybatis-config.xml");
            SqlSession sqlSession = new SqlSessionFactoryBuilder().build(resourceAsReader).openSession();
            UserDao mapper = sqlSession.getMapper(UserDao.class);
            List<User> users = mapper.findByNameAndSex(null, "男");
            for (User user:users) {
                System.out.println(user);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

测试结果如下图所示:

测试结果

注:上述代码中,where元素标签会自动识别其标签内是否有返回值,若有,就插入一个where。此外,若标签返回的内容是以and或者or开头的,会自动剔除。

3、if+trim用法

    在MyBatis中,除了使用if+where实现多条件查询,还有一个更为灵活的元素trim可以替代之前的做法。
    trim元素也会自动识别其他标签内是否有返回值,则在自己包含的内容前面加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefix和suffix;trim也可以把包含内容的首部的某些内容覆盖(即忽略),或者把尾部的某些内容覆盖,与之对应的属性是prefixOverrides和suffixOverrides;正因为trim有这样强大的功能,我们才可以利用trim来替代where元素,并实现与where元素相同的效果,接下来就改造上一个示例来实现多用户查询操作。
<mapper namespace="com.fan.dao.UserDao">
    <select id="findByNameAndSex" resultType="com.fan.entity.User">
         select * from users
         <trim prefix="where" prefixOverrides="and|or">
            <if test="uname!=null and uname!=''">
                   and name like "%"#{uname}"%"
            </if>
            <if test="usex!=null">
                   and sex=#{usex}
            </if>
         </trim>
    </select>
</mapper>
通过该示例代码,我们来了解一下trim的属性。
\diamondsuit prefix:前缀,作用是通过自动识别是否有返回值后,在trim包含的内容上加上前缀,如此处的where。
\diamondsuit suffix:后缀,作用是在trim包含的内容上加上后缀。
\diamondsuit prefixOverrides:对于trim内容的首部进行指定内容(如此处的“and | or”)的忽略。
\diamondsuit suffixOverrides:对于trim包含内容的尾部进行指定内容的忽略。
上一篇 下一篇

猜你喜欢

热点阅读