Mybatis----动态SQL四大标签

四大标签

if
choose(when,other)
trim(where,set):where封装查询条件,set封装修改条件,都是和if结合使用
foreach

下面来一一介绍并测试,测试内容是基于上一篇的JavaBean和数据库Mybatis----resultMap详解及应用(一)

一、if标签

结合where标签:

需求:查询员工:携带了哪个字段,查询条件就带上这个字段的值。

mapper接口中的方法和对应的映射规则:
public List<Employee> getEmpsByConditionIf(Employee e);

<select id="getEmpsByConditionIf" resultType="bean.Employee">
        select * from tbl_employee
        <!-- where 1=1 -->
        <where>
        <!-- OGNL表达式:从参数中取值进行判断-->
            <if test="id!=null">
                id=#{id}
            </if>
            <if test="lastName!=null and lastName!=''">
                and last_name like #{lastName}
            </if>
            <if test="email!=null and email.trim()!=''">
                and email=#{email}
            </if>
            <!--ognl会进行字符串和数字的转换 "0"==0是可以的-->
            <if test="gender==0 or gender==1">
                and gender=#{gender};
            </if>
        </where>
    </select>

在未使用 < where >标签之前,会出现一些sql拼装的问题,例如查询条件中id为空,sql语句where后面直接跟着一个and显然是不合理的。解决办法如下:

方法一:where关键字后面拼上1=1,之后所有情况的sql语句都会带上...where 1=1 and...	 
方法二:mybatis使用where标签来将所有的查询条件包括在内.mybatis自动将where标签中拼装的
                sql多出来的and或者or去掉,只会去掉第一个,推荐将所有的and或or写在句首

结合set标签:实现添加员工方法

需求: 修改员工:携带了哪个字段,修改条件就带上这个字段的值。

mapper接口中的方法和对应的映射规则:
public void updateEmp(Employee e);

<update id="updateEmp">
        update tbl_employee
        <set>
            <if test="lastName!=null">
                last_name=#{lastName},
            </if>
            <if test="email!=null">
                email=#{email},
            </if>
            <if test="gender!=null">
                gender=#{gender}
            </if>
        </set>
        where id=#{id}
二、trim标签
prefix:             前缀:在整个拼接的动态sql语句前加上前缀
prefixOverride:     前缀覆盖:去掉整个字符串前面多余的字符
suffix:             后缀:给拼串后额整个字符串加一个后缀
suffixOverride:     后缀覆盖:去掉后面多余的字符

方法声明和映射规则:
public List<Employee> getEmpsByConditionTrim(Employee e);

<select id="getEmpsByConditionTrim" resultType="bean.Employee">
        select * from tbl_employee
        <!--自定义字符串截取规则-->
        <trim prefix="where" suffixOverrides="and">
            <if test="id!=null">
                id=#{id} and
            </if>
            <if test="lastName!=null and lastName!=''">
                last_name like #{lastName} and
            </if>
            <if test="email!=null and email.trim()!=''">
                email=#{email} and
            </if>
            <!--ognl会进行字符串和数字的转换 "0"==0是可以的-->
            <if test="gender==0 or gender==1">
                gender=#{gender} and;
            </if>
        </trim>
    </select>

使用trim标签实现上面的新增员工方法:
set关键字放在prefix中,逗号放在suffixOverride中,如果后续没有条件,多余的逗号将被剪掉

<update id="updateEmp">
        update tbl_employee
        <trim prefix="set" suffixOverrides=",">
            <if test="lastName!=null">
                last_name=#{lastName},
            </if>
            <if test="email!=null">
                email=#{email},
            </if>
            <if test="gender!=null">
                gender=#{gender}
            </if>
        </trim>
    </update>  

三、choose标签

它的作用类似于switch-case

方法声明和映射规则:
public List<Employee> getEmpsByConditionChos(Employee e);

<select id="getEmpsByConditionChos" resultType="bean.Employee">
        select * from tbl_employee
        <where>
            <!-- 如果带了id就用id查,如果带了lastName就用lastName查;都没有则查询全部
            	只会进入其中一个分支-->
            <choose>
                <when test="id!=null">
                    id=#{id}
                </when>
                <when test="lastName!=null">
                    last_name like #{lastName}
                </when>
                <when test="email!=null">
                    email=#{email}
                </when>
                <otherwise>
                    1=1
                </otherwise>
            </choose>
        </where>
    </select>

四、foreach标签

foreach标签中的属性:

collection:指定要遍历的集合的key:
            list类型的参数会特殊处理封装在map中,map的key就叫list
item:每次遍历出的元素起一个变量名,方便引用,使用 #{} 取值
index:索引
          如果遍历的是一个list:
                index,指定的变量保存了当前索引
                item,就是保存当前遍历元素的值
          如果遍历的是一个map:
                index,指定的变量就是保存了当前遍历元素的key
                item,就是保存当前遍历元素的值
close:以什么结束
open:以什么开始
separator:每次遍历元素的分隔符

需求一:查询员工ID集合里面包含的所有相关员工信息

方法声明和映射规则:
public List<Employee> getEmpsByConditionForeach(@Param("ids") List<Integer> list);
可以使用@param()注解给参数命名。

<select id="getEmpsByConditionForeach" resultType="bean.Employee">
        select * from tbl_employee where id in
        <foreach collection="ids" item="item_id" separator="," open="(" close=")">
            #{item_id}
        </foreach>
</select>


需求二:批量保存:

方法声明和映射规则:
public void addEmps(@Param("emps") List<Employee> emps);

方法一:MySQL支持…values(),(),()的方式批量插入

    <insert id="addEmps">
        insert into tbl_employee(last_name,email,gender,d_id)
        values
        <foreach collection="emps" item="emp" separator=",">
           (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
        </foreach>
    </insert>

方法二:使用foreach直接插入完整的sql语句

需要注意的是要开启MySQL的多句查询,在dbconfig.properties中的jdbc.url 后面加入
?allowMultiQueries=ture,同时要求数据库引擎支持,可将MySQL的引擎切换到InnoDB。

<insert id="addEmps">
        <foreach collection="emps" item="emp" separator=";">
            insert into tbl_employee(last_name,email,gender,d_id)
            values (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
        </foreach>
    </insert>

五、动态SQL四大标签测试
package MybatisTest;

import bean.Department;
import bean.Employee;
import dao.EmployeeMapperDynamicSQL;
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.Test;

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

public class MybatisTest {
    public SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "config\\mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void test1() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession openSession = sqlSessionFactory.openSession();
        try {
            EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
            Employee employee = new Employee(null,"%o%",null,null);

            //测试if标签
            List<Employee> empsByConditionIf = mapper.getEmpsByConditionIf(employee);
            for (Employee employee1 :empsByConditionIf) {
                System.out.println(employee1);
            }
            /*查询的时候如果某些条件没带可能会导致sql拼装有问题
              方法一:where关键字后面拼上1=1,之后所有情况的sql语句都会带上...where 1=1 and...
              方法二:mybatis使用where标签来将所有的查询条件包括在内.mybatis自动将where标签中拼装的
                    sql多出来的and或者or去掉,只会去掉第一个,推荐将所有的and或or写在句首
            */
            
            //测试trim标签
            List<Employee> empsByConditionTrim = mapper.getEmpsByConditionTrim(employee);
            for (Employee employee1 :empsByConditionTrim) {
                System.out.println(employee1);
            }

            //测试choose(when,otherwise)
            List<Employee> empsByConditionChos = mapper.getEmpsByConditionChos(employee);
            System.out.println(empsByConditionChos);

            //测试set标签
            //直接使用set关键字会导致逗号问题,使用set或trim标签解决
            Employee employee1 = new Employee(1, null, "112233@qq.com", null);
            mapper.updateEmp(employee1);
            openSession.commit();

            //测试foreach标签
            List<Employee> empsByConditionForeach = mapper.getEmpsByConditionForeach(Arrays.asList(1, 4, 5));
            for (Employee e :empsByConditionForeach) {
                System.out.println(e);
            }
        }finally {
            openSession.close();
        }
    }

    //测试批量添加
    @Test
    public void test2() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession openSession = sqlSessionFactory.openSession();
        try {
            EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
            List<Employee> emps=new ArrayList<>();
            emps.add(new Employee(null,"timmy","987456@163.com","1",new Department(1)));
            emps.add(new Employee(null,"allen","555666@163.com","0",new Department(2)));
            mapper.addEmps(emps);
            openSession.commit();
        }finally {
            openSession.close();
        }
    }
}

六、两个内置参数和sql标签

还剩一点点内容,就记在一起吧。

方法传递过来的参数不只可以被用来判断,取值。。。
mybatis默认还有两个内置参数:
  _parameter:代表传过来的整个参数
        单个参数:_parameter就是这个参数
        多个参数:参数会被封装为一个map
  _databaseId:如果配置了DatabaseIdProvider标签。
        _databaseId就是代表当前数据库的别名

查两种数据库
    以前的方法每个select 后面带一个databaseId
    现在通过if标签结合_databaseId :全局配置文件中配置了databaseIdProvider之后

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

public List<Employee> getEmpsTestInnerParameter(Employee e);

<select id="getEmpsTestInnerParameter" resultType="bean.Employee">
        <bind name="_lastName" value="'%'+lastName+'%'"/>
        <if test="_databaseId==mysql">
            select * from tbl_employee
            <if test="_parameter!=null">
                where last_name=#{_lastName}
            </if>
        </if>
        <if test="_databaseId==oracle">
            select * from employees
            <if test="_parameter!=null">
                where last_name=#{_parameter.lastName}
            </if>
        </if>
    </select>

测试:一般不会这样做模糊查询,将%直接放在参数中比较灵活,而不用修改xml文件

@Test
public void testInnerParam() throws IOException{
	sqlsessionFactory sqlSessionFactory = getsqisessionFactory();
	sqlsession openSession = sqlSessionFactory.openSession();
	try{
		EmployeeMapperDynamicsQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
		Employee employee2 = newEmployee();
		employee2.setLastName("e"); 
		List<Employee> list = mapper.getEmpsTestInnerParameter(employee2)
		for (Employee employee : list){
			system.out.println(employee);
		}
	}
}
七、sql标签–与增删改同级的标签

抽取共同的sql片段,一般抽取要查询的列名或者插入的列名。

insert into tbl_employee values(
   <include refid="insertColumn">
        <property name="testColumn" value="abc"
   </include>
   )
   
<sql id="insertColumn">
   <if test="_databaseId==mysql">
       employee_id,last_name,email,${testColumn}
   </if>
   <if test="databaseId==oracle">
       last_name,gender,email,d_id
   </if>
</sql>

include标签内部还可以自定义一些property,sql标签内还能引用,用$取值 ${testColumn}
上面的testColumn是错误的,数据库中并没有这一列,仅作为演示。这样发送的sql语句还能看到insert …values(…,abc)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值