MyBatis--动态sql语句

环境搭建

  • 目录结构

在这里插入图片描述

  • MyBatis配置文件
<?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="properties/datasource.properties"/>
    <settings>
        <!--开启懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <environments default="mysql">
        <!--定义开发时的环境配置
            链接mysql数据库
        -->
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
        <environment id="oracle">
            <transactionManager type="JDBC"/>
            <dataSource type="UNPOOLED">
                <property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
                <property name="url" value="jdbc:oracle:thin:@localhost:1521:mldn "/>
                <property name="username" value="scott"/>
                <property name="password" value="tiger"/>
            </dataSource>
        </environment>
    </environments>
    <databaseIdProvider type="DB_VENDOR">
        <property name="MySql" value="mysql"/>
        <property name="Oracle" value="oracle"/>
    </databaseIdProvider>
    <!--注册sql-->
    <mappers>
        <mapper resource="config/MyBatisDynamicSQLDAO.xml"/>
    </mappers>
</configuration>


ONGL表达式

在这里插入图片描述

if判断

在这里插入图片描述

  • 示例:使用If动态拼装sql语句
  • 如果遇到要使用双引号或者大于号小于号这样的特殊符号可以使用转义字符
  • OBGL支持逻辑运算表达式"与&",“或|” 也可以使用"and"代替与,使用"or"代替"或"

在这里插入图片描述

  • 设置接口方法
public List<Employee> getEmps(Employee employee);
  • 配置sql映射文件
    <select id="getEmps" resultType="mao.shu.vo.Employee">
        SELECT id, ename, age, job, dept_id
        FROM employee
        WHERE
         <!-- 使用if进行判断
            test为判断的表达式
            id由外部方法传入的参数
         -->
        <if test="id!=null">
            id = #{id}
        </if>
<!--
    and表示"&&" 逻辑判断符
   &quot;为转义字符,表示双引号"",也可以使用''单引号表示
-->
        <if test="ename!=null and &quot;&quot;.equals(ename)">
            AND ename = #{ename} AND
        </if>
        <!-- or表示 "||"逻辑运算符-->
        <if test="age==1 or age==2">
            age = #{age} AND
        </if>
    </select>
  • 测试代码
package mao.shu.dao;

import mao.shu.vo.Employee;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

import static org.junit.Assert.*;

public class MyBatisDynamicSQLDAOTest {

    private SqlSession sqlSession;
    @Before
    public void before() throws IOException {
        String resource = "config/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        this.sqlSession = sqlSessionFactory.openSession();
    }

    @After
    public void after(){
        this.sqlSession.commit();
        this.sqlSession.close();
    }

    @Test
    public void getEmps(){
        MyBatisDynamicSQLDAO dynamicSQLDAO = this.sqlSession.getMapper(MyBatisDynamicSQLDAO.class);
        Employee employee = new Employee();
        employee.setId(1);
        List<Employee> emps = dynamicSQLDAO.getEmps(employee);
        System.out.println(emps);

    }
}
  • 测试结果

在这里插入图片描述

where查询条件

  • 查询的时候如果第一个条件不存在,则可能会出现将后面 “and xxx” 拼接到sql语句中,造成sql语法错误.

在这里插入图片描述

  • 使用<where>标签代替sql查询条件的"WHERE"

  • 修改sql映射文件

    <select id="getEmps" resultType="mao.shu.vo.Employee">
        SELECT id, ename, age, job, dept_id
        FROM employee
        <where>
            <if test="id!=null">
                id = #{id}
            </if>
            <if test="ename!=null and !&quot;&quot;.equals(ename)">
                AND ename = #{ename}
            </if>      
            <if test="age>=0 ">
                AND age = #{age}
            </if>
        </where>
    </select>
  • <where>标签会根据条件自动消除掉sql语句中前面部分的"AND" 字符

在这里插入图片描述

trim自定义字符串截取

  • <trim>标签可以使用自定义sql语句的拼凑和裁剪部分

在这里插入图片描述

  • 示例:使用<trim>标签拼凑"WHERE"部分
   <select id="testTrim" resultType="mao.shu.vo.Employee">
        SELECT id, ename, age, job, dept_id
        FROM employee

        <!--
            <trim>标签拼凑字符串
            prefix:添加前缀
            prefixOverrides:控制用字符串覆盖前缀
            suffix:定制后缀字符串
            suffixOverrides="AND":覆盖最后 AND 的字符串
        -->
        <trim prefix="WHERE"  suffixOverrides="AND">
            
            <if test="id!=null">
                id = #{id} AND
            </if>

            <if test="ename!=null and !&quot;&quot;.equals(ename)">
                 ename = #{ename} AND
            </if>

            <if test="age>=0">
                 age = #{age} AND
            </if>
        </trim>
    </select>
  • 测试代码
    @Test
    public void testTrim(){
        MyBatisDynamicSQLDAO dynamicSQLDAO = this.sqlSession.getMapper(MyBatisDynamicSQLDAO.class);
        Employee employee = new Employee();
    
        employee.setAge(22);
        List<Employee> emps = dynamicSQLDAO.testTrim(employee);
        System.out.println(emps);

    }

在这里插入图片描述

choose分支选择

  • 分支选择类似于java中的swtitch-case,但是<choosse>分支只会选择一个.

在这里插入图片描述

  • 示例:
    <select id="testChoose" resultType="mao.shu.vo.Employee">
        SELECT id, ename, age, job, dept_id
        FROM employee
        <where>
            <choose>
                <when test="id!=null">
                    id=#{id}
                </when>
                <when test="ename!=null and ''.equals(ename)">
                  ename LIKE #{ename}
                </when>
                <when test="age!=null and age>0">
                    age = #{age}
                </when>
            </choose>
        </where>
    </select>
  • 测试方法
    @Test
    public void testChoose(){
        MyBatisDynamicSQLDAO dynamicSQLDAO = this.sqlSession.getMapper(MyBatisDynamicSQLDAO.class);
        Employee employee = new Employee();
        employee.setId(1);
        employee.setAge(22);
        employee.setEname("xiemaoshu");
        List<Employee> emps = dynamicSQLDAO.testChoose(employee);
        System.out.println(emps);

    }
  • <choose>标签只会选择其中一个

在这里插入图片描述

set与if结合动态更新

  • 使用<set>标签描述更新sql语句的设置部分,可以自动的取出多余的","号

在这里插入图片描述

  • 示例:
  • 定义接口更新方法
    public void updateEmp(Employee employee);
  • 定义sql映射文件
   <select id="updateEmp" resultType="mao.shu.vo.Employee">
        UPDATE employee
        <set>
            <if test="ename!=null and !''.equals(ename)">
                ename=#{ename},
            </if>
            <if test="age!=null and age>0">
                age=#{age},
            </if>

            <if test="job!=null and !''.equals(job)">
                job=#{job},
            </if>
        </set>
        <where>
            id=#{id}
        </where>
    </select>
  • 测试方法
    @Test
    public void updateEmp() {
        MyBatisDynamicSQLDAO dynamicSQLDAO = this.sqlSession.getMapper(MyBatisDynamicSQLDAO.class);
        Employee employee = new Employee();
        employee.setId(1);
        employee.setAge(22);
        employee.setEname("xiemaoshu");
        employee.setJob("流浪地球");
        dynamicSQLDAO.updateEmp(employee);
    }
  • 被修改的数据

在这里插入图片描述

遍历集合

  • 当接口方法定义了集合类型的参数,则可以使用<foreach>标签遍历集合,

  • 默认情况下集合参数会被MyBatis封装到Map集合中,使用"list"或者 “collection”,可以获取到集合参数

  • 当然也可以在接口方法参数上设置@Param 注解定义保存集合的key
    在这里插入图片描述
    在这里插入图片描述

  • 示例:

  • 接口定义的方法

    public List<Employee> getEmpsForeach(@Param("ids") List<Integer> ids);
  • sql映射文件
    <select id="getEmpsForeach" resultType="mao.shu.vo.Employee">
        SELECT  id, ename, age, job, dept_id
        FROM employee

          <!--
            遍历集合
            collection:要便利的集合,ids是调用方法的参数
            open:开始字符
            close:结束字符
            separator:分隔符,以逗号为","
          -->
        <foreach collection="ids" item="id" open=" WHERE id IN (" close=")" separator=",">
            #{id}
        </foreach>
    </select>
  • 测试方法
    @Test
    public void getEmpsForeach() {
        MyBatisDynamicSQLDAO dynamicSQLDAO = this.sqlSession.getMapper(MyBatisDynamicSQLDAO.class);

        List<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(4);
        ids.add(3);
        List<Employee> emps = dynamicSQLDAO.getEmpsForeach(ids);

        for(Employee emp : emps){
            System.out.println(emp);
        }


    }

在这里插入图片描述

MySQL下foreach两种插入方式

  • 示例:定义批量添加方法
    public void addBathEmp(@Param("emps") List<Employee> emps);
  • 第一种方式以MySQL "values(),(),()"的方式
    <insert id="addBathEmp"  useGeneratedKeys="true">
        INSERT INTO employee(ename, age, job, dept_id)
        VALUES
        <foreach collection="emps" item="emp" separator=",">
            (#{emp.ename},#{emp.age},#{emp.job},#{emp.deptID})
        </foreach>
    </insert>
  • 测试方法
   @Test
    public void addBathEmp() {
        MyBatisDynamicSQLDAO dynamicSQLDAO = this.sqlSession.getMapper(MyBatisDynamicSQLDAO.class);

        List<Employee> emps = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Employee temp = new Employee();
            temp.setJob("批量添加测试"+i);
            temp.setEname("批量添加测试"+i);
            temp.setAge(i+20);
            Department tempDept = new Department();
            tempDept.setDeptID(i%2==0?2:1);
            temp.setDepartment(tempDept);
            emps.add(temp);
        }

       dynamicSQLDAO.addBathEmp(emps);


    }

在这里插入图片描述

  • 添加的数据

在这里插入图片描述

  • 第二种方式:每次遍历都拼凑一个完整的sql插入语句,使用";"分号分隔每条sql语句
  • MySQL需要在链接时开启"allowMultiQueries=true",的属性,才允许一次执行多条sql语句
  • 修改数据库连接的url
jdbc.url=jdbc:mysql://localhost:3306/mybatisdb?allowMultiQueries=true
  • 修改sql映射文件
    <insert id="addBathEmp" useGeneratedKeys="true">

        <foreach collection="emps" item="emp" separator=";">
            INSERT INTO employee(ename, age, job, dept_id)
            VALUES

            (#{emp.ename},#{emp.age},#{emp.job},#{emp.department.deptID})
        </foreach>
    </insert>
  • 推荐使用第一种方式

Oracle使用foreach批量增加的两种方式

  1. 第一种方式使用"begin…end"完成批量操作
    <!--
        oracle数据库可以在"BEGIN"和"END"之间编写多条sql语句
    -->
    <insert id="addBathEmp" databaseId="oracle">
        BEGIN
        <foreach collection="emps" item="emp" >
            INSERT INTO emp(empno, ename, job,deptno)
            VALUES
            (EMPLOYEE_SEQ.nextval,#{emp.ename},#{emp.job},#{emp.department.deptID});
        </foreach>
        END;
    </insert>
  • 测试方法
    @Test
    public void addBathEmp() {
        MyBatisDynamicSQLDAO dynamicSQLDAO = this.sqlSession.getMapper(MyBatisDynamicSQLDAO.class);

        List<Employee> emps = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Employee temp = new Employee();
            temp.setJob("test"+i);
            temp.setEname("test"+i);
            temp.setAge(i+20);
            Department tempDept = new Department();
            tempDept.setDeptID(i%2==0?20:10);
            temp.setDepartment(tempDept);
            emps.add(temp);
        }

       dynamicSQLDAO.addBathEmp(emps);


    }

在这里插入图片描述

  • 添加的数据

在这里插入图片描述
2. 使用中间表的方式,进行批量操作

  • oracle中有一个 dual 表,这个表是一个中间表,可以用于显示数据使用
    <!--oracle批量操作,使用中间表的方式-->
    <insert id="addBathEmp" databaseId="oracle">
        insert into emp(EMPNO, ename, job)
        select EMPLOYEE_SEQ.nextval, ename, job

        from (
        <foreach collection="emps" item="emp" separator=" union">
            select #{emp.ename} ename, #{emp.job} job
            from dual
        </foreach>
        )

    </insert>

内置参数parameter&databaseId

  • 在MyBatis中内置了两个参数
    1. _parameter:描述方法传进来的参数,如果是多个参数则会被封装到"Map"集合中,则_parameter参数描述的是这个Map集合
    2. _databaseId:描述数据库厂商的别名

在这里插入图片描述

  • 示例:使用内置参数
   <select id="builtInParam" resultMap="builtInParam_resultMap" >
        <if test="_databaseId=='oracle'">
            <if test="_parameter!=null">
                SELECT empno,ename,job
                FROM EMP
            </if>
        </if>
        <if test="_databaseId=='mysql'">
            <if test="_parameter!=null">
                SELECT id, ename, age, job, dept_id
                FROM employee
            </if>
        </if>

    </select>

bind绑定

  • bind:可以讲一个OGNL表达式的值绑定到一个变量中,方便后来引用这个变量.

  • <bind>中的属性

    1. name:定义的变量名
    2. value:变量表达式
  • 示例:

  <select id="builtInParam" resultMap="builtInParam_resultMap">
        <if test="_databaseId=='oracle'">

            SELECT empno,ename,job
            FROM EMP
            <if test="ename!=null">
                <bind name="_ename" value="'%'+ename+'%'"/>
              WHERE ename LIKE #{_ename}
            </if>
        </if>

    </select>

sql抽取可重用的片段

  1. <sql>标签可以将一些重用的字段,保存起来,为其他便签提供一个id,其他标签就可以使用<include>标签引用<sql>标签中的内容.
  2. <sql>标签中可以使用<if>或其他标签进行逻辑判断,动态生成内部内容
  3. <include>标签也可以自定义一些变量,而在<sql>标签中使用"${}"的方式进行引用
        <include refid="empField">
        <!-- 传递自定义的参数-->
            <property name="test" value="testField"/>
        </include>
  • 示例:
    <!--定义重用字段-->
    <sql id="empField">
        <if test="_databaseId=='oracle'">
            empno id, ename, job,deptno dept_id
        </if>
        <if test="_databaseId=='mysql'">
            id, ename,job, dept_id
        </if>


    </sql>
    <sql id="empTableName">
        <if test="_databaseId=='oracle'">
            emp
        </if>
        <if test="_databaseId=='mysql'">
            employee
        </if>


    </sql>
  • 引用<sql>字段

    <select id="builtInParam" resultMap="builtInParam_resultMap">

        SELECT
        <include refid="empField"></include>
        FROM
        <include refid="empTableName"></include>
        <if test="ename!=null">
            <bind name="_ename" value="'%'+ename+'%'"/>
            WHERE ename LIKE #{_ename}
        </if>


    </select>
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值