JavaSSM框架-MyBatis 框架(五)
9. 动态 SQL
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。
9.1 if & where & trim 标签
-
DynamicSQLMapper 接口
public interface DynamicSQLMapper {List<Emp> getEmpByCondition(Emp emp); }
-
DynamicSQLMapper 映射文件
if 标签可通过test属性
的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行
注意:其本质就是SQL拼接,如果if条件为true,则直接把if标签里的内容拼接在SQL语句后面
<!--注意开启下划线映射驼峰--> <!--List<Emp> getEmpByCondition(@Param("emp") Emp emp);--> <select id="getEmpByCondition" resultType="Emp">select * from t_emp where<!--注意test里面写判断语句,即if括号中的内容,要用and连接,因为&&是特殊字符--><if test="empName != null and empName != '' ">emp_name = #{empName}</if><if test="age != null">and age = #{age}</if><if test="gender != null and gender != '' ">and gender = #{gender}</if> </select>
注意:上述SQL语句存在的问题,当第一个
if
条件不成立时,而第二个成立时,SQL语句就会变成,select * from t_emp where and age = #{age}
显然是错误的,当所有if
都不成立时,SQL语句最后就多了个where,也是错误的,以下有三种解决方案:-
解决方案一:在where后面加1=1,并且在第一个if前加and
<select id="getEmpByCondition" resultType="Emp">select * from t_emp where 1 = 1<!--在第一个if里面加and,同时在where后面加上1=1,--><if test="empName != null and empName != '' ">and emp_name = #{empName}</if><if test="age != null">and age = #{age}</if><if test="gender != null and gender != '' ">and gender = #{gender}</if> </select>
-
解决方案二:使用
where标签
where和if一般结合使用:
-
若
where标签中有条件成立
,会自动生成where关键字
-
若
where
标签中的if
条件都不满足,则where标签没有任何功能,即不会添加where关键字 -
若
where
标签中的if
条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉
注意:
where标签不能去掉条件最后多余的and,也不能添加and
<select id="getEmpByCondition" resultType="Emp">select * from t_emp<where><if test="empName != null and empName != '' ">emp_name = #{empName}</if><if test="age != null">and age = #{age}</if><if test="gender != null and gender != '' ">and gender = #{gender}</if></where> </select>
where和if配合工作流程如下:
-
首先是
if
进行判断,如果条件成立,则将其拼接,例如如果第二个if
语句,即age != null
成立,且第三个if
也成立,那么最后where
标签里就会变成如下内容,即将符合条件的语句拼接在一起<where>and age = #{age} and gender = #{gender} </where>
-
而后便是
where标签
执行,where
标签会将标签里的内容中,前面的and
去掉,并在最前面加上where
,最后便会变成如下内容:where age = #{age} and gender = #{gender}
-
-
解决方案三:使用
trim标签
trim
用于去掉或添加标签中的内容常用属性:
-
prefix
:在trim标签中的内容的前面添加
某些内容 -
prefixOverrides
:在trim标签中的内容的前面去掉
某些内容 -
suffix
:在trim标签中的内容的后面添加
某些内容 -
suffixOverrides
:在trim标签中的内容的后面去掉
某些内容
<select id="getEmpByCondition" resultType="Emp">select * from t_emp<trim prefix="where" suffixOverrides="and"><!--注意test里面写判断语句,即if括号中的内容,要用and连接,因为&&是特殊字符--><if test="empName != null and empName != '' ">emp_name = #{empName} and</if><if test="age != null">age = #{age} and</if><if test="gender != null and gender != '' ">gender = #{gender} and</if></trim></select>
注意:其原理与
where标签
类似,首先判断if
条件否成立,然后进行拼接,最后对trim标签
的内容进行相应的操作 -
-
-
Junit 测试
@Test public void testGetEmpByCondition() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);// Emp emp = new Emp(null,"张三",19,"男");Emp emp = new Emp(null,"",19,"男");List<Emp> empList = mapper.getEmpByCondition(emp);System.out.println(empList); }
9.2 choose、when、otherwise
choose、when、 otherwise:
- 相当于java中的if…else if…else
- when至少设置一个,otherwise 最多设置一个
-
DynamicSQLMapper 接口
public interface DynamicSQLMapper {List<Emp> getEmpByChoose(Emp emp); }
-
DynamicSQLMapper 映射文件
<!--List<Emp> getEmpByChoose(Emp emp);--> <select id="getEmpByChoose" resultType="Emp">select * from t_emp<where><choose><!--其中第一个when就相当于if,后面的when相当于if else,最后的otherwise相当于else其实就是多分支结构,也类似与switch语句--><when test="empName != null and empName != ''">emp_name = #{empName}</when><when test="age != null">age = #{age}</when><when test="gender != null and gender != '' ">gender = #{gender}</when><otherwise></otherwise></choose></where> </select>
-
Junit 测试
@Test public void testGetEmpByChoose() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);Emp emp = new Emp(null,"",19,"男");List<Emp> empList = mapper.getEmpByChoose(emp);System.out.println(empList); }
9.3 foreach 标签
foreach 标签属性如下:
collection
:设置要循环的数组或集合item
:用一个字符串表示数组或集合中的每一个数据separator
:设置每次循环的数据之间的分隔符open
:循环的所有内容以什么开始close
:循环的所有内容以什么结束
-
DynamicSQLMapper 接口
public interface DynamicSQLMapper {void insertMoreEmp(@Param("emps") List<Emp> emps);void deleteMoreEmp(@Param("empIds") Integer[] empIds); }
-
DynamicSQLMapper 映射文件
<!--void insertMoreEmp(@Param("emps") List<Emp> emps);--> <insert id="insertMoreEmp">insert into t_emp values<foreach collection="emps" item="emp" separator=",">(null,#{emp.empName},#{emp.age},#{emp.gender},null)</foreach> </insert><!--void deleteMoreEmp(Integer[] empIds);--> <delete id="deleteMoreEmp"><!--第一种方式--><!--delete from t_emp where emp_id in(<foreach collection="empIds" item="empId" separator=",">#{empId}</foreach>)--><!--第二种方式:open表示以什么开始,close表示以什么结束--><!--delete from t_emp where emp_id in<foreach collection="empIds" item="empId" separator="," open="(" close=")">#{empId}</foreach>--><!--第三种方式:注意下面的separator="or",or的左右不用加空格也行,会自动在前后加空格-->delete from t_emp where<foreach collection="empIds" item="empId" separator="or">emp_id = #{empId}</foreach> </delete>
-
Junit 测试
@Test public void testInsertMoreEmp() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);List<Emp> emps = new ArrayList<>();emps.add(new Emp(null,"小明1",19,"男"));emps.add(new Emp(null,"小明2",19,"男"));emps.add(new Emp(null,"小明3",19,"男"));mapper.insertMoreEmp(emps); }@Test public void testDeleteMoreEmp() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);Integer[] empIds = new Integer[]{8,9,10};mapper.deleteMoreEmp(empIds); }
9.4 SQL片段
sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入,其
include标签
属性refid
填sql
片段的id
<sql id="empColumns">emp_id,emp_name,age,gender,dept_id
</sql>
<select id="getEmpById" resultType="Emp" >select <include refid="empColumns"></include> from t_emp where emp_id = #{empId}
</select>