2023-01-12

一、Mybatis动态SQL

即将SQL动态化

同时Mybatis的动态SQL支持OFNL表达式,OGNL(Object Graph Navigation Language)对象图导航语言。

1、先搭建环境

(1)创建一个“maven”模块,命名为“day04_mybatis”

(2)在“day04_mybatis”中的“pom.xml”中的<project>标签内部添加依赖,即添加jar包

<dependencies>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

(3)在"day04_mybatis.src.main.resources"中添加"db.properties(连接数据库,里面的形式是:key=value),需要设置4个值(driver、url、username、password)"和“log4j.xml”

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="UTF-8" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
        </layout>
    </appender>
    <logger name="java.sql">
        <level value="debug"/>
    </logger>
    <logger name="org.apache.ibatis">
        <level value="info"/>
    </logger>
    <root>
        <level value="debug" />
        <appender-ref ref="STDOUT" />
    </root>
</log4j:configuration>

(4)在“day04_mybatis.src.resources”中添加“mybatis-config.xml”

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--    设置属性-->
    <properties resource="db.properties"></properties>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!--        延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--        延迟加载的属性-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    <typeAliases>
        <package name="com.hh.mybatis.pojo"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${db.driver}"/>
                <property name="url" value="${db.url}"/>
                <property name="username" value="${db.username}"/>
                <property name="password" value="${db.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/EmployeeMapper.xml"></mapper>
    </mappers>
</configuration>

(5)在“day04_mybatis.src.main.java”中创建“com.hh.mybatis.pojo”和“com.hh.mybatis.mapper”。之后在“day04_mybatis.src.main.resources”中创建“mapper”文件夹,在“mapper”文件夹下创建“EmployeeMapper.xml”

(6)在“pojo”文件夹下创建“Dept”、“Employee”。在“mapper”文件夹下创建“EmployeeMapper”接口并添加代码

public interface EmployeeMapper {
    /**
     * 按条件查询员工信息(条件不确定)
     * @return
     */
    public List<Employee> selectEmpByOpr(Employee employee);
}

(7)EmployeeMapper.xml中的映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hh.mybatis.mapper.EmployeeMapper" >
<!-- 按条件查询员工信息(条件不确定)-->
    <select id="selectEmpByOpr" resultType="employee">
        select
            id,
            last_name,
            email,
            salary,
            dept_id,
        from
            tbl_employee
    </select>
</mapper>

(8)在“day04_mybatis.src.test.java"中创建测试类“TestDynamicSql”

public class TestDynamicSql {
    @Test
    public void testDynamicSql() throws Exception{
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee employee = new Employee();
        List<Employee> employees = employeeMapper.selectEmpByOpr(employee);
        for (Employee employee1 : employees) {
            System.out.println("employee1 = " + employee1);
        }
    }
}

(9)注意:

如果出现“java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corres”这种问题报错时,可以将sql语句先在“SQLyog”中先写一遍,运行,如果运行无误,之后将代码再放入“映射文件”中,即可

2、进行动态SQL设置

(1)注意:在动态SQL中“test”中放置的是“属性”

(2)动态SQL<if>标签

用于完成简单的判断

<select id="selectEmpByOpr" resultType="employee">
        SELECT
            id,
            last_name,
            email,
            salary
        FROM
            tbl_employee
        WHERE
            <if test="id != null">
                id = #{id}
            </if>
            <if test="lastName != null">
                and last_name = #{lastName}
            </if>
            <if test="email != null">
                and email = #{email}
            </if>
            <if test="salary != null">
                and salary = #{salary}
            </if>
    </select>

测试类

public class TestDynamicSql {
    @Test
    public void testDynamicSql() throws Exception{
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee employee = new Employee();
        //动态标签
        employee.setId(1);
//        employee.setSalary(50.0);
        List<Employee> employees = employeeMapper.selectEmpByOpr(employee);
        for (Employee employee1 : employees) {
            System.out.println("employee1 = " + employee1);
        }
    }
}

注意:动态参数中<if>,无参数时报错,没有第一个参数也报错。

(3)动态SQL:<where>标签

where用于解决SQL语句中where关键字以及条件前面的and或者or的问题

<select id="selectEmpByOpr" resultType="employee">
        SELECT
            id,
            last_name,
            email,
            salary
        FROM
            tbl_employee
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="lastName != null">
                and last_name = #{lastName}
            </if>
            <if test="email != null">
                and email = #{email}
            </if>
            <if test="salary != null">
                and salary = #{salary}
            </if>
        </where>
    </select>

(3)动态SQL:<trim>

可以在条件判断完的SQL语句前后添加或者去掉指定的字符

标签中的属性:

①prefix:添加前缀

②prefixOverrides:去掉前缀

③suffix:添加后缀

④suffixOverrides:去掉后缀

例如:

    <select id="selectEmpByOprTrim" resultType="employee">
         SELECT
            id,
            last_name,
            email,
            salary
        FROM
            tbl_employee
        <trim prefix="where" suffixOverrides="and">
            <if test="id != null">
                 id = #{id} and
            </if>
            <if test="lastName != null">
                last_name = #{lastName} and
            </if>
            <if test="email != null">
                email = #{email} and
            </if>
            <if test="salary != null">
                salary = #{salary}
            </if>
        </trim>
    </select>

(4)动态SQL:<set>

用于解决修改操作中SQL语句中可能多出逗号的问题

在“EmployeeMapper”接口中添加方法

/**
     * 按条件修改员工信息(条件不确定)
     * @param employee
     */
    public void updateEmpByOpr(Employee employee);

映射文件

<update id="updateEmpByOpr">
        update
            tbl_employee
        <set>
            <if test="lastName != null">
                last_name = #{lastName},
            </if>
            <if test="email != null">
                email = #{email},
            </if>
            <if test="salary != null">
                salary = #{salary}
            </if>
        </set>
        where
           id = #{id}
</update>

(5)动态SQL标签:<choose>

类似于java中if-else(switch-case)结构

    <update id="updateEmpByOneOpr">
        SELECT
            id,
            last_name,
            email,
            salary
        FROM
            tbl_employee
        <where>
             <choose>
                 <when test="id != null">
                     id = #{id}
                 </when>
                 <when test="email != null">
                     email = #{email}
                 </when>
                 <when test="salary != null">
                     salary = #{salary}
                 </when>
                 <otherwise>
                     1=1
                 </otherwise>
             </choose>
        </where>
    </update>

(6)动态SQL标签:<foreach>

类似于java中的for循环

collection:要迭代的集合

item:当前从集合中迭代出的元素

separator:元素与元素之间的分隔符

①“EmployeeMapper”接口中的函数

/**
     * 通过多个id获取员工信息
     * @param ids
     * @return
     */
    public List<Employee> selectEmpByIds(@Param("ids") List<Integer> ids);

②映射文件

<select id="selectEmpByIds" resultType="employee">
        SELECT
            id,
            last_name,
            email,
            salary
        FROM
            tbl_employee
        <where>
            id in
            (
            <foreach collection="ids" item="id" separator=",">
                #{id}
            </foreach>
            )
        </where>
    </select>

③测试主要代码

List<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(3);
        ids.add(4);
        List<Employee> employees = employeeMapper.selectEmpByIds(ids);
        for (Employee employee1 : employees) {
            System.out.println("employee1 = " + employee1);
        }

(7)sql标签

提取可重用SQL片段

    <sql id="select_employee">
        SELECT
            id,
            last_name,
            email,
            salary
        FROM
            tbl_employee
    </sql>
    <sql id="emp_col">
        id,
        last_name,
        email,
        salary
    </sql>
<!-- 按条件查询员工信息(条件不确定)-->
    <select id="selectEmpByOpr" resultType="employee">
        select
            <include refid="emp_col"></include>
        from
            tbl_employee
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="lastName != null">
                and last_name = #{lastName}
            </if>
            <if test="email != null">
                and email = #{email}
            </if>
            <if test="salary != null">
                and salary = #{salary}
            </if>
        </where>
    </select>