MyBatis 动态SQL

来源:互联网 发布:中小学题库软件 编辑:程序博客网 时间:2024/06/16 02:27

有些时候,静态的SQL脚本并不能很好的满足我们的业务场景,我们需要根据用户捉摸不定的输入,来动态地拼接成一个SQL。例如,多条件组合查询时,我们需要根据用户输入的条件来动态的拼接一个where条件等。本篇来介绍mybatis对动态sql的支持。

数据准备

为了能够更好地演示我的示例代码,我先在mysql中创建一个数据表

CREATE TABLE `students2` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `class` varchar(50) DEFAULT NULL,  `name` varchar(50) DEFAULT NULL,  `gender` int(11) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

然后加入几条初始数据

insert  into `students2`(`class`,`name`,`gender`) values ('1501','张三',1),('1501','小红',2),('1502','小明',1),('1501','kite',1);

IF条件

假如我们现在要对Students2表进行多条件组合查询,条件包括班级(class),姓名(name)和性别(gender),我们先假设class是必填的,name和gender是选填的,我们针对这个情况,写一个动态sql。

首先,定义我们的实体类

public class Student2 {    private int id;    private String className;    private String name;    private int gender;    // getters and setters ......}

然后是我们的sql映射文件

<resultMap type="Student2" id="Student2Result">    <id property="id" column="id"/>    <result property="className" column="class"/>    <result property="name" column="name"/>    <result property="gender" column="gender"/></resultMap><select id="searchStudents" resultMap="Student2Result" parameterType="hashmap">    SELECT * FROM STUDENTS2 WHERE CLASS=#{className}    <if test="name != null">        AND NAME LIKE #{name}    </if>    <if test="gender != null">        AND GENDER = #{gender}    </if></select>

由于数据表有一列的名字为class,该名字是Java的保留字,我们为Student2类添加了一个名为className的字段。由于两者不一致,所以再resultMap中通过<result property="className" column="class"/>进行关联。

接下来,我们定义一个映射接口

public interface StudentMapper {    public List<Student2> searchStudents(Map<String, Object> map);}

然后,在Main方法中进行调用

public static void main(String[] args) {    SqlSession sqlSession = MyBatisSqlSessionFactory.openSession();    try {        StudentMapper studentMapper=sqlSession.getMapper(StudentMapper.class);                  Map<String, Object> map = new HashMap<String, Object>();        map.put("className", "1501");        //map.put("name", "%ki%");        map.put("name", "%三%");        //map.put("gender", 2);        List<Student2> studts= studentMapper.searchStudents(map);        System.out.println("查询结果总数:"+studts.size());        for(Student2 item :studts){            System.out.println("class:"+item.getClassName()+",name:"+item.getName()+            ",gender:"+item.getGender());        }    } catch (Exception e) {        e.printStackTrace();    }finally {        sqlSession.close();    }}

运行这段java代码后,会打印出下面的结果

查询结果总数:1class:1501,name:张三,gender:1

map中有些条件注释掉了,读者可以多试几个条件。
如果查询条件中含有中文字符而不能查出结果的话,请在mysql连接字符串中加入字符集的参数,如下:

<dataSource type="POOLED">    <property name="driver" value="com.mysql.jdbc.Driver" />    <property name="url" value="jdbc:mysql://localhost:3306/students?useUnicode=true&amp;characterEncoding=utf-8" />    <property name="username" value="root" />    <property name="password" value="root" /></dataSource>

WHERE条件

我在上面的组合条件中假设了班级为必填,如果所有条件都可以选填的话,当用户不输入任何条件时,会造成sql语句中包含一个空的WHERE条件。mybatis提供了WHERE关键字,当所有的where查询参数都为空时,将自动去掉where部分,而不造成语法错误。
修改后,sql映射文件中的<select>部分将变为

<select id="searchStudents" resultMap="Student2Result"    parameterType="hashmap">    SELECT * FROM STUDENTS2    <where>        <if test="className != null">            CLASS=#{className}        </if>        <if test="name != null">            AND NAME LIKE #{name}        </if>        <if test="gender != null">            AND GENDER = #{gender}        </if>    </where></select>

当然,这种方式比较优雅,我还有比较偷懒的方式,就是:

<select id="searchStudents" resultMap="Student2Result"    parameterType="hashmap">    SELECT * FROM STUDENTS2 WHERE 1=1     <if test="className != null">        AND CLASS=#{className}    </if>    <if test="name != null">        AND NAME LIKE #{name}    </if>    <if test="gender != null">        AND GENDER = #{gender}    </if></select>

foreach循环

如果sql语句包含in子句,并且这个参数是动态的,可以使用foreach来实现。来看两段示例代码体会一下

<select id="searchCoursesByTutors" parameterType="map"    resultMap="CourseResult">    SELECT * FROM COURSES    <if test="tutorIds != null">        <where>            <foreach item="tutorId" collection="tutorIds">                OR tutor_id=#{tutorId}            </foreach>        </where>    </if></select>

tutorIds是map参数中的一个元素,foreach会动态地生成sql。还有下面这个例子

<select id="searchCoursesByTutors" parameterType="map"    resultMap="CourseResult">    SELECT * FROM COURSES    <if test="tutorIds != null">        <where>            tutor_id IN            <foreach item="tutorId" collection="tutorIds" open="("                separator="," close=")">                #{tutorId}            </foreach>        </where>    </if></select>

set条件

写update语句时,有时会传递过来一个对象和map,我们希望将对象中不为null的属性写入set子句中,通过set可以实现。

<update id="updateStudent" parameterType="Student">    update students    <set>        <if test="name != null">name=#{name},</if>        <if test="email != null">email=#{email},</if>        <if test="phone != null">phone=#{phone},</if>    </set>    where stud_id=#{id}</update>

如果读者发现foreach和set部分的示例代码中属性的名字跟最初的建的表的列名不一致,我想告诉你,不要在意这些细节!如果你能通过这篇博客学会mybatis中的动态sql的语法,我的目的就达到了!快跑!

0 0