溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何理解MyBatis動態(tài)SQL

發(fā)布時間:2021-09-30 14:46:10 來源:億速云 閱讀:122 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“如何理解MyBatis動態(tài)SQL”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“如何理解MyBatis動態(tài)SQL”吧!

目錄
  • 前言

  • 動態(tài)sql

    • 1.先看一下模塊目錄結(jié)構(gòu)

    • 2.物理建模和邏輯建模

    • 3. 引入依賴

    • 4.全局配置文件

    • 5.sql共性抽取文件

    • 6.mapper接口

  • if

    • 靜態(tài)sql:

    • 動態(tài)sql:

  • where

    • 用if標(biāo)簽的動態(tài)sql:

    • where和if的動態(tài)sql:

  • trim

    • trim的動態(tài)sql

    • trim標(biāo)簽:

  • set

    • trim的動態(tài)sql:

    • set的動態(tài)sql

    • set標(biāo)簽的作用:

  • choose、when、otherwise

    • 動態(tài)sql

  • foreach

    • 1.動態(tài)sql

    • 2.動態(tài)sql

    • 批量查詢:foreach標(biāo)簽

  • 測試程序

    前言

    前面mysql都是通過靜態(tài)sql進(jìn)行查詢的,但是如果業(yè)務(wù)復(fù)雜的時候,我們會遇到引號問題,或者多一個空格,這就使得sql代碼編寫錯誤了,所以為了解決這個問題,我們有了動態(tài)sql。

    Mybatis框架的動態(tài)SQL技術(shù)是一種根據(jù)特定條件動態(tài)拼裝SQL語句的功能,它存在的意義是為了解決拼接SQL語句字符串時的痛點問題。具體是通過標(biāo)簽來實現(xiàn)的。

    動態(tài)sql

    1.先看一下模塊目錄結(jié)構(gòu)

    在類路徑的resources下的mapper包下創(chuàng)建sql.xml文件(共性抽?。?/p>

    如何理解MyBatis動態(tài)SQL

    2.物理建模和邏輯建模

    這里省略物理建模步驟,要求數(shù)據(jù)庫的表與pojo類要對應(yīng)。

    package pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Employee {
        private Integer empId;
        private String empName;
        private Double empSalary;
    
    }

    3. 引入依賴

    把之前的log4j復(fù)制到類路徑resouces下,另外我們引入依賴后的pom.xml如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>day03-mybatis02-dynamic</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <dependencies>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.8</version>
                <scope>provided</scope>
            </dependency>
    
            <!-- Mybatis核心 -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.7</version>
            </dependency>
    
            <!-- junit測試 -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
    
            <!-- MySQL驅(qū)動 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.3</version>
                <scope>runtime</scope>
            </dependency>
    
            <!-- log4j日志 -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
        </dependencies>
    
    </project>

    4.全局配置文件

    <?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>
        <!--駝峰映射-->
        <settings>
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>
        <!--類型別名映射-->
        <typeAliases>
            <package name="pojo"/>
        </typeAliases>
        <!--環(huán)境配置-->
        <environments default="dev">
            <environment id="dev">
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="POOLED">
                    <property name="username" value="root"/>
                    <property name="password" value="888888"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                </dataSource>
                    
            </environment>
        </environments>
        <!--路徑映射-->
        <mappers>
            <mapper resource="mapper/sql.xml"/>
            <package name="mapper"/>
        </mappers>
    </configuration>

    注意: 這里有駝峰映射,別名映射,路徑映射和路徑映射。和以前的不同的是,我們這里做了sql語句的共性抽取,所以得加一個sql的路徑映射 <mapper resource="mapper/sql.xml"/>

    5.sql共性抽取文件

    在類路徑resources下的包mapper下創(chuàng)建一個sql.xml(因為我們sql是要寫在映射文件中,自己本身也是映射文件,所以需要寫在mapper下)。到要用的時候,在映射路徑文件中需要用到這個sql語句的地方加入 <include refid="mapper.sql.mySelectSql"></include>。

    <?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="mapper.sql">
    
            <sql id="mySelectSql">
        select emp_id,emp_name,emp_salary from t_emp
    </sql>
    
    
    </mapper>

    共性抽取文件也可以不配置,這時候直接在映射文件中把要執(zhí)行的語句重新編寫就行了。

    6.mapper接口

    一共有七個方法

    package mapper;
    
    import org.apache.ibatis.annotations.Param;
    import pojo.Employee;
    
    import java.util.List;
    
    public interface EmployeeMapper {
    
         //根據(jù)員工的empId查詢大于該empId的所有員工,如果empId為null,則查詢?nèi)w員工
        List<Employee> selectEmployeeListByEmpId(Integer empId);
    
        /**
         * 查詢大于傳入的empId并且工資大于傳入的empSalary的員工集合,如果傳入的empId為null,則不考慮empId條件
         * 傳入的empSalary為null則不考慮empSalary的條件
         */
        List<Employee> selectEmployeeListByEmpIdAndEmpSalary(@Param("empId") Integer empId, @Param("empSalary") Double empSalary);
    
        /**
         * 根據(jù)empId更新員工信息,如果某個值為null,則不更新這個字段
         */
        void updateEmployee(Employee employee);
    
        /**
         * 根據(jù)emp_id查詢員工信息,如果0<emp_id<6,那么就查詢所有大于該emp_id的員工,如果emp_id是大于6,那么就查詢所有小于該emp_id的員工
         * 如果是其它情況,則查詢所有員工信息
        
         */
        List<Employee> selectEmployeeList(Integer empId);
    
        /**
         * 添加員工信息 
         */
        void insertEmployee(Employee employee);
    
        /**
         * 批量添加員工集合    
         */
        void insertEmployeeList(@Param("employeeList") List<Employee> employeeList);
    
        /**
         * 根據(jù)員工的id集合查詢員工集
         */
        List<Employee> selectEmployeeListByEmpIdList(List<Integer> idList);
    }

    if

    目標(biāo):根據(jù)員工的empId查詢大于該empId的所有員工,如果empId為null,則查詢?nèi)w員工。

    Dao接口的方法為:
    List<Employee> selectEmployeeListByEmpId(Integer empId);

    靜態(tài)sql:

    <select id="selectEmployeeListByEmpId" resultType="Employee">
    
        <include refid="mapper.sql.mySelectSql"></include> where emp_id>#{empId}
    
    </select>

    動態(tài)sql:

    <select id="selectEmployeeListByEmpId" resultType="Employee">
         <include refid="mapper.sql.mySelectSql"></include>
         <if test="empId != null">
             where emp_id>#{empId}
         </if>
     </select>

    <include refid="mapper.sql.mySelectSql"></include>表示引用抽取出的sql片段,也可以直接寫sql語句。如果是靜態(tài)sql,當(dāng)id為null時,查詢出來的是空,動態(tài)sql則可以查出全部。if標(biāo)簽里面有test屬性名,作為判斷語句。

    where

    目標(biāo):

    • 查詢大于傳入的empId并且工資大于傳入的empSalary的員工集合

    • 如果傳入的empId為null,則不考慮empId條件

    • 傳入的empSalary為null則不考慮empSalary的條件

    Dao接口方法:

    List<Employee> selectEmployeeListByEmpIdAndEmpSalary(@Param("empId") Integer empId, @Param("empSalary") Double empSalary);

    用if標(biāo)簽的動態(tài)sql:

    <select id="selectEmployeeListByEmpIdAndEmpSalary" resultType="Employee">
        <include refid="mapper.sql.mySelectSql"></include> where
       <if test="empId != null">
                emp_id>#{empId}
            </if>
            <if test="empSalary != null">
               and emp_salary>#{empSalary}
            </if>

    這里可以看到,如果empSalary為空,那么sql語句為select * from t_emp where emp_id >#{empId},但是如果empId為空,那么sql語句為select * from t_emp where and emp_salary>#{empSalary},很明顯這個是錯的,if標(biāo)簽在這里就不適用了。所以我們用where標(biāo)簽,或者trim標(biāo)簽。

    where和if的動態(tài)sql:

    <select id="selectEmployeeListByEmpIdAndEmpSalary" resultType="Employee">
        <include refid="mapper.sql.mySelectSql"></include>
       
        <where>
            <if test="empId != null">
                emp_id>#{empId}
            </if>
            <if test="empSalary != null">
               and emp_salary>#{empSalary}
            </if>
        </where>
    </select>

    where標(biāo)簽的作用:

    • 在第一個條件之前自動添加WHERE關(guān)鍵字

    • 自動去掉第一個條件前的連接符(AND、OR等等)

    trim

    trim是修建的意思,其實就是去頭去尾,這里還是根據(jù)上面那個方法

    trim的動態(tài)sql

    <select id="selectEmployeeListByEmpIdAndEmpSalary" resultType="Employee">
        <include refid="mapper.sql.mySelectSql"></include>
        <trim prefix="WHERE" prefixOverrides="AND|OR">
            <if test="empId != null">
                emp_id>#{empId}
            </if>
    
            <if test="empSalary != null">
                AND emp_salary>#{empSalary}
            </if>
        </trim>
    </select>

    trim標(biāo)簽:

    • prefix:指定要動態(tài)添加的前綴

    • suffix屬性:指定要動態(tài)添加的后綴

    • prefixOverrides:指定要動態(tài)去掉的前綴,使用“|”分隔有可能的多個值

    • suffixOverrides屬性:指定要動態(tài)去掉的后綴,使用“|”分隔有可能的多個值

    set

    目標(biāo):根據(jù)empId更新員工信息,如果某個值為null,則不更新這個字段

    Dao接口方法:
    void updateEmployee(Employee employee);
    我們先用上面的trim標(biāo)簽來解決一下這個問題,

    trim的動態(tài)sql:

    <update id="updateEmployee" >
        <trim prefix="set" prefixOverrides=",">
            <if test="empName!=null">
                emp_name=#{empName}
            </if>
            <if test="empSalary!=null">
                , emp_salary=#{empSalary}
            </if>
        </trim>
        where emp_id=#{empId}
    </update>

    set的動態(tài)sql

    <update id="updateEmployee" >
        update t_emp
         <set >
             <if test="empName!=null">
                 emp_name=#{empName}
             </if>
             <if test="empSalary!=null">
                , emp_salary=#{empSalary}
             </if>
         </set>

    可以看出

    set標(biāo)簽的作用:

    • 自動在要修改的第一個字段之前添加SET關(guān)鍵字

    • 去掉要修改的第一個字段前的連接符(,)

    choose、when、otherwise

    目標(biāo):

    • 根據(jù)emp_id查詢員工信息,如果0<emp_id<6,那么就查詢所有大于該emp_id的員工

    • 如果emp_id是大于6,那么就查詢所有小于該emp_id的員工

    • 如果是其它情況,則查詢所有員工信息

    Dao接口方法:
    List<Employee> selectEmployeeList(Integer empId);

    動態(tài)sql

    <select id="selectEmployeeList" resultType="employee">
      
        <include refid="mapper.sql.mySelectSql"></include> where
        <choose>
        <!--&lt;是<號的轉(zhuǎn)義字符-->
            <when test="empId>0 and empId&lt;6">
                emp_id>#{empId}
            </when>
            <when test="empId>6">
                emp_id&lt;#{empId}
            </when>
            <otherwise>
                1==1
            </otherwise>
        </choose>
    
    </select>

    choose、when、otherwise
    相當(dāng)于if ... else if... else if ... else

    • 如果某一個when的條件成立,則不會繼續(xù)判斷后續(xù)的when

    • 如果所有的when都不成立,則會拼接otherwise標(biāo)簽中的內(nèi)容

    foreach

    目標(biāo)1:批量添加員工信息

    Dao接口方法:

    void insertEmployeeList(@Param("employeeList") List employeeList);

    1.動態(tài)sql

    <insert id="insertEmployeeList">
        insert into t_emp(emp_name,emp_salary)values
        <!--collection標(biāo)簽可以寫list,collection,
        或者自己自己定義參數(shù)名@Param("employeeList") List<Employee> employeeList-->
        <foreach collection="employeeList" separator="," item="emp">
            (#{emp.empName},#{emp.empSalary})
        </foreach>
    </insert>

    目標(biāo)2:根據(jù)多個id查詢多個員工信息

    Dao接口

    List selectEmployeeListByEmpIdList(List idList);

    2.動態(tài)sql

    <select id="selectEmployeeListByEmpIdList" resultType="employee">
        <include refid="mapper.sql.mySelectSql"></include>
         <foreach collection="collection" item="id" separator="," open="where emp_id in (" close=")">
             #{id}
         </foreach>
    </select>

    批量查詢:foreach標(biāo)簽

    1. collection屬性: 表示要遍歷的對象,如果要遍歷的參數(shù)使用@Param注解取名了就使用該名字,如果沒有取名List,或者collection。

    2. item屬性: 表示遍歷出來的元素,我們到時候要拼接SQL語句就得使用這個元素: 如果遍歷出來的元素是POJO對象, 那么我們就通過 #{遍歷出來的元素.POJO的屬性} 獲取數(shù)據(jù);如果遍歷出來的元素是簡單類型的數(shù)據(jù),那么我們就使用 #{遍歷出來的元素} 獲取這個簡單類型數(shù)據(jù)

    3. separator屬性: 遍歷出來的元素之間的分隔符

    4. open屬性: 在遍歷出來的第一個元素之前添加前綴

    5. close屬性: 在遍歷出來的最后一個元素之后添加后綴

    測試程序

    import mapper.EmployeeMapper;
    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 pojo.Employee;
    
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    public class Test {
        private EmployeeMapper employeeMapper;
        private InputStream is;
        private SqlSession sqlSession;
        @Before
        public void init() throws Exception{
            //目標(biāo):獲取EmployeeMapper接口的代理對象,并且使用該對象調(diào)用selectEmployee(1)方法,然后返回Employee對象
            //1. 將全局配置文件轉(zhuǎn)成字節(jié)輸入流
            is = Resources.getResourceAsStream("mybatisConfig.xml");
            //2. 創(chuàng)建SqlSessionFactoryBuilder對象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            //3. 使用構(gòu)建者模式創(chuàng)建SqlSessionFactory對象
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            //4. 使用工廠模式創(chuàng)建一個SqlSession對象
            sqlSession = sqlSessionFactory.openSession();
            //5. 使用動態(tài)代理模式,創(chuàng)建EmployeeMapper接口的代理對象
            employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        }
    
    
        @After
        public void after() throws Exception{
            //提交事務(wù)!!!
            sqlSession.commit();
            //7. 關(guān)閉資源
            is.close();
            sqlSession.close();
        }
    
        @org.junit.Test
        public void testSelectEmployeeListByEmpId(){
            System.out.println(employeeMapper.selectEmployeeListByEmpId(null));
        }
    
        @org.junit.Test
        public void testSelectEmployeeListByEmpIdAndEmpSalary(){
            System.out.println(employeeMapper.selectEmployeeListByEmpIdAndEmpSalary(2, 300d));
        }
    
        @org.junit.Test
        public void testUpdateEmployee(){
            Employee employee = new Employee(3,"celia", 9000d);
    
            employeeMapper.updateEmployee(employee);
        }
    
        @org.junit.Test
        public void testSelectEmployeeList(){
        System.out.println(employeeMapper.selectEmployeeList(7));
    }
    
       @org.junit.Test
       public void testInsertEmployee(){
            employeeMapper.insertEmployee(new Employee(null,"tom",300d));
        }
    
        @org.junit.Test
        public void testInsertEmployeeList(){
            List<Employee> employeeList = new ArrayList<>();
            for (int i = 11; i <=20 ; i++) {
                employeeList.add(new Employee(null,"aobama"+i,2000d));
            }
    
            employeeMapper.insertEmployeeList(employeeList);
    
        }
    
        @org.junit.Test
        public void testSelectEmployeeListByEmpIdList(){
            List<Integer> idList = new ArrayList<>();
            idList.add(23);
            idList.add(33);
            idList.add(32);
            idList.add(21);
            idList.add(22);
            System.out.println(employeeMapper.selectEmployeeListByEmpIdList(idList));
        }
    
    
    }

    到此,相信大家對“如何理解MyBatis動態(tài)SQL”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI