Mybatis框架学习笔记 --- [动态sql的使用]

Posted 小智RE0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis框架学习笔记 --- [动态sql的使用]相关的知识,希望对你有一定的参考价值。

mybatis3版本的文档 -->mybatis文档

写在前面
Ok,也是进行到动态sql这部分了;
需要说明的是,后来我又给员工表添加了一个记录年龄的列,当然在员工类中也添加了属性以及它的getset方法;构造方法;toString();这些也都加上这个属性了.

1. if 标签与 where 标签

使用 if标签 可以对条件进行判断;
一般是结合在其他标签中使用;

where 标签 可以动态地添加where关键字 ,并且可以做到 自动去除后面不符合条件时 的and或者or关键字

<where>元素会进行判断,如果它包含的标签中有返回值的话,它就插入一个where
如果标签返回的内容是以 ANDOR 开头,它会自动去除掉ANDOR

比如说,我要设置两个查询条件,姓名和性别筛选查询人员的信息,但是也可以不通过这两个条件进行查询,也可以一个条件去查询,而不使用另一个条件;
当然你可以写4个SQL语句进行处理;
但这时用动态SQL查询的话,还是比较方便的,只需要写一次sql语句就能同时兼顾这四种情况.

在实例中看看效果

Ok,在EmployeeMapper职工类的持久层接口写个方法;根据年龄和性别动态查询员工的信息;

//根据条件动态查询员工列表; 姓名/性别; @Param()为参数作注解,到时候SQL那边就用注解里面的名称;
List<Employee> getEmpByNameOrAge(@Param("name") String name, @Param("sex")String sex);

EmployeeMapper.xml中添加对应的sql;

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--注意 这里对应空间为持久层映射接口-->
<mapper namespace="com.xiaozhi.mapper.EmployeeMapper">
<!--定义映射关系map-->
    <resultMap id="empmap" type="employee">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="sex" property="sex"/>
        <!--关联部门表-->
        <association property="dept" javaType="dept">
            <result column="dname" property="name"/>
        </association>
        <!--关联用户管理表-->
        <association property="user" javaType="user">
            <result column="account" property="account"/>
        </association>
    </resultMap>
    
    <!--根据姓名/性别动态查询员工-->
    <select id="getEmpByNameOrAge" resultMap="empmap">
        SELECT
          e.`id`,
          e.`name`,
          e.`sex`,
          e.`age`,
          d.`name` dname ,
          u.`account`
          FROM t_employee e
          LEFT JOIN  t_dept d ON  e.`deptID`=d.`id`
          LEFT JOIN  t_user u ON  u.`id`=e.`optionId`
          <where>
              <if test="name != null &amp; name !='' ">
                  e.name = #{name}
              </if>
              <if test="sex != null &amp; sex !='' ">
                  and e.sex= #{sex}
              </if>
          </where>
    </select>
</mapper>    

当然;在核心配置文件mybatis-config.xml里面还要配置员工的mapper映射文件地址;
(我这个是之前配置了的)

测试使用;

这里也是直接把上次的那个页面查询框改了一下;
Mybatis框架学习笔记(5) —[多表关联查询 连接到前端页面显示]

OK,就从service包下的EmployeeService来一步步修改吧;

public class EmployeeService {
//根据姓名/性别动态查询员工;
    public List<Employee> getEmpByNameOrAge(String name,String sex){
        //调用工具类;
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        //获取代理对象;
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        //调用方法;
        List<Employee> list = mapper.getEmpByNameOrAge(name, sex);
        //关闭sqlSession;
        sqlSession.close();
        return list;
    }
}

servlet包下的EmployeeServlet

public class EmployeeServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter out=null;

        //获取到标记参数;
        String mark = req.getParameter("mark");
        if(mark.equals("empList")){
            try{
                //请求编码;响应解码;
                resp.setContentType("text/html;charset=utf-8");
                //会以流的方式返回;
                out = resp.getWriter();

                //获取参数;
                String name = req.getParameter("name");
                String sex = req.getParameter("sex");

                System.out.println("正在查询姓名为--:"+name+"性别为==>"+sex);
                //调用服务层处理;
                EmployeeService employeeService = new EmployeeService();
                List<Employee> empByNameOrAge = employeeService.getEmpByNameOrAge(name, sex);
                //控制台输出测试;
                //empByNameOrAge.forEach(System.out::println);
                //不为空就发送出去;
                if(!empByNameOrAge.isEmpty()){
                    out.print(new Gson().toJson(empByNameOrAge));
                }else {
                    out.print(0);//-->不存在,提示信息
                }
            }catch (Exception e){
                e.printStackTrace();
                out.print(500);//-->服务器错误;
            }
        }
        
    }
}        

当然,没使用到注解的话,这里还要手动配置一下;web.xml

 <!--配置员工servlet-->
    <servlet>
        <servlet-name>empServlet</servlet-name>
        <servlet-class>com.xiaozhi.servlet.EmployeeServlet</servlet-class>
    </servlet>
    <!--servlet映射-->
    <servlet-mapping>
        <servlet-name>empServlet</servlet-name>
        <url-pattern>/do/emp</url-pattern>
    </servlet-mapping>

employee.html员工的列表访问页面;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>员工列表</title>
    <!--部署jquery-->
    <script src="js/jquery.1.8.3.min.js" type="text/javascript"></script>

    <script type="text/javascript">
        //页面打开时发送请求;这里不传递姓名和性别查询条件;
        $(function () {
            $.get("do/emp", {mark:"empList"}, function (res) {
                //测试获取的数据;
                //console.log(res)
                if(res==500){
                    alert("抱歉,服务器出了点问题");
                }else if(res==0){
                    //弹框提示;
                    alert("抱歉,暂时没有员工!")
                }else {
                    //拼接存入表格;
                    var str2="";
                    for (var i = 0; i < res.length; i++) {
                        str2+="<tr  align='center'>";
                        str2+="<td>"+(i+1)+"</td>";
                        str2+="<td>"+res[i].name+ "</td>";
                        str2+="<td>"+res[i].sex+ "</td>";
                        str2+="<td>"+res[i].dept.name+ "</td>";
                        str2+="<td>"+res[i].user.account+ "</td>";
                        str2+="</tr>";
                    }
                    $("#table").append(str2);
                }

            }, "json");
        });

        //点击搜索时,查询员工;
        function getEmp(){
            //先获取到输入框的值
            var name = $("input[name='name']").val();
            var sex = $("input[name='sex']").val();

                //发送请求;进行查询;注意携带姓名或性别
                $.get("do/emp",{mark:"empList",name:name,sex:sex},function (res){
                    //测试响应的数据;
                    console.log(res)
                    if(res==500){
                        alert("抱歉,服务器出了点问题");
                    }else if(res==0){
                        //清除表格的信息;
                        $("tr:gt(0)").remove();
                        //弹框提示;
                        alert("该员工不存在!!!");
                    }else {
                        //同样地,先清除全部的信息;
                        $("tr:gt(0)").remove();
                        //拼接显示数据;
                        var str4="";
                        for (var i = 0; i < res.length; i++) {
                            str4 += "<tr  align='center'>";
                            str4 += "<td>" + (i+1) + "</td>";
                            str4 += "<td>" + res[i].name + "</td>";
                            str4 += "<td>" + res[i].sex + "</td>";
                            str4 += "<td>" + res[i].dept.name + "</td>";
                            str4 += "<td>" + res[i].user.account + "</td>";
                            str4 += "</tr>";
                        }
                        $("#table").append(str4);
                    }
                },"json");
        }

        //点击全部员工,刷新页面;
        function getAll(){
            location.reload();
        }

    </script>
</head>
<body>
<form style="width: 1080px" id="form">
    <label>
        姓名:<input type="text" name="name" placeholder="请输入要查询的员工姓名:"/>
        性别:<input type="text" name="sex" placeholder="请输入要查询的员工性别:"/>
    </label>
    <input  type="button" value="搜索" onclick="getEmp()"/>
    <!--当然为了能够调回之前的全部员工,再次加载一次这个页面-->
    <input type="button" value="显示全部员工" onclick="getAll()">
</form>
<br/>
<!--显示的表格-->
<table width="100%" border="1" cellspacing="0" id="table">
    <th>编号</th>
    <th>员工姓名</th>
    <th>员工性别</th>
    <th>所属部门</th>
    <th>操作人</th>
</table>
</body>
</html>

配置号tomcat服务器后,Ok启动,看看效果

(1)首次访问时,这时的查询是不带条件的;

所以这边接收到的也是null空值,所以不会去拼接where子句

试试用姓名查询;

(1)这里接收到了姓名,以及空字符串性别; 根据姓名去进行了查询;但是查询时没有拼接性别哦;

这时因为之前在写SQL语句时,在<if>标签内加了条件判断

(3)试试只输入性别进行查询

接收到的姓名为空字符串;则在查询时只根据性别条件进行查询,<where>标签去掉了and关键字

(4)根据姓名和性别查询

当然,姓名和性别都被作为条件进行了查询

(5)那么打开了页面后,不输入查询条件,直接查询呢,这时就会直接查询出所有的员工,因为接收到的姓名和性别的输入框都是空的字符串

由于接收到了空字符串,所以自动去掉了后面的where查询条件


其实,不使用的<where> 标签,也能做到动态SQL的查询;也算是一种奇技淫巧了;
直接在查询条件时拼接一段成立的条件,比如说在where 查询条件后拼接 1=1;防止后面的条件若都不符合就查询输出所有的数据;
那就试试吧;
EmployeeMapper.xml中修改SQL语句;把之前的暂时注释掉;

    <!--根据姓名/性别动态查询员工  奇技淫巧-->
<select id="getEmpByNameOrAge" resultMap="empmap">
    SELECT
    e.`id`,
    e.`name`,
    e.`sex`,
    e.`age`,
    d.`name` dname ,
    u.`account`
    FROM t_employee e
    LEFT JOIN t_dept d ON e.`deptID`=d.`id`
    LEFT JOIN t_user u ON u.`id`=e.`optionId`
    where 1=1
    <if test="name != null &amp; name !='' ">
        and e.name = #{name}
    </if>
    <if test="sex != null &amp; sex !='' ">
        and e.sex= #{sex}
    </if>
</select>

查询试试;
例如仅通过性别为条件进行查询

查询效果还是不错的

2.trim标签

自定义 trim 元素来定制 where 元素
使用trim标签也可以完成where子句的拼接,以及and/or这种关键字的去除
这时prefix="where" 表示可拼接的前缀;prefixOverrides= "and|or"表示若出现这些关键字 根据情况就自动去除掉

OK,那就试试吧,注释掉之前的查询SQL;

<!--使用trim标签 -->
<!--根据姓名/性别动态查询员工-->
<select id="getEmpByNameOrAge" resultMap="empmap">
    SELECT
    e.`id`,
    e.`name`,
    e.`age`,
    e.`sex`,
    d.`name` dname ,
    u.`account`
    FROM t_employee e
    LEFT JOIN t_dept d ON e.`deptID`=d.`id`
    LEFT JOIN t_user u ON u.`id`=e.`optionId`
    <trim prefix=以上是关于Mybatis框架学习笔记 --- [动态sql的使用]的主要内容,如果未能解决你的问题,请参考以下文章

框架学习笔记之Mybatis

Mybatis学习笔记-动态SQL

Mybatis学习笔记

学习笔记——Mybatis动态SQL

Mybatis学习笔记:动态SQL

Mybatis 学习笔记总结