一、前言
什么是动态SQL? 动态SQL有什么作用?
如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
通常使用动态 SQL 不可能是独立的一部分,MyBatis 使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。
动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多的元素需要来了解。MyBatis3大大提升了它们,现在用不到原先一半的元素就可以了。MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。
Mybatis的动态SQL功能正是为了解决这种问题, 通过 if, choose, when, otherwise, trim, where, set, foreach标签,可组合成非常灵活的SQL语句,从而提高开发人员的效率。下面我们通过相关案例感受Mybatis动态SQL的魅力吧。
二、案例
定义一个接口类EmpMapper,新增接口方法findEmpByConditions
public interface EmpMapper {
/**
* 根据条件查询员工信息
* @param id
* @return
*/
public Emp findEmpByConditions(Emp emp);
}
定义一个EmpMapper.xml文件,配置如下
<?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="com.queen.mybatis.mapper.EmpMapper">
<select id="findEmpByConditions" resultType="com.queen.mybatis.bean.Emp">
select id,emp_name empName,emp_email empEmail, dept_id deptId
from t_emp
where
<if test="id!=null">
id=#{id}
</if>
<if test="empName!=null and empName!=""">
and emp_name=#{empName}
</if>
<if test="empEmail!=null and empEmail.trim()!=""">
and emp_mail=#{empEmail}
</if>
<if test="deptId!=null">
and dept_id=#{deptId}
</if>
</select>
</mapper>
如上,这条语句提供了一些可选的条件查找员工信息的功能。如果传入的id 不为空, 那么才会SQL才拼接id = #{id};如果传入的empName不为空, 那么才会SQL才拼接emp_name= #{empName};实现多条件查询。
新增测试类MyBatisTest,添加测试方法testFindEmpByCondition
@Test
public void testFindEmpByCondition() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmpMapper mapper = openSession.getMapper(EmpMapper.class);
Emp emp = new Emp(1,"ant","ant@sina.com",null);
Emp empFind = mapper.findEmpByConditions(emp);
System.out.println(empFind);
} finally {
openSession.close();
}
}
控制台打印结果如下
select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where id=? and emp_name=? and emp_mail=?
2017-08-12 17:17:18,454 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpByConditions]-[DEBUG] ==> Parameters: 1(Integer), ant(String), queen(String)
2017-08-12 17:17:18,494 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpByConditions]-[DEBUG] <== Total: 1
Emp [id=1, empName=ant, empEmail=ant@sina.com, deptId=1]
如上,所有的条件都不为空除了deptId,打印的SQL是select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where id=? and emp_name=? and emp_name=? 这样的,少了deptId条件。我们尝试,将deptId不为空,作为参数传递进来,这时候SQL语句又会变成什么样呢?
修改测试方法
Emp emp = new Emp(1,"ant","ant@sina.com",1);
再次测试,控制台打印结果如下
2017-08-12 17:29:37,925 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpByConditions]-[DEBUG] ==> Preparing: select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where id=? and emp_name=? and emp_name=? and dept_id=?
2017-08-12 17:29:37,988 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpByConditions]-[DEBUG] ==> Parameters: 1(Integer), ant(String), ant(String), 1(Integer)
通过if语句的使用,我们实现了参数条件的动态封装拼接SQL,但是这种方式有点小问题哟,不知道细心的您有木有发现,如果当id不为空的时候,SQL语句会变成这样”select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where and emp_name=? and emp_mail=? “,不管三七二十一,where条件后直接拼了and,造成SQL语法错误。报错信息如下:
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'and emp_name='queen'
and emp_name='queen'
and dept_i' at line 6
### The error may exist in EmpMapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where and emp_name=? and emp_name=? and dept_id=?
如上,控制台报错,说MySQL语法错误。那么这个时候我们要怎么处理这种问题,这里我们有两种解决方案,可以参考下一节
《老司机学习MyBatis之如何使用动态SQL之使用where条件》
=======欢迎大家拍砖,小手一抖,多多点赞哟!=======
版权声明:本文为博主原创文章,允许转载,但转载必须标明出处。