目录
一、动态 SQL简单介绍
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
二、标签简单介绍
1.if
<select id="findif" parameterType="entity.Student" resultType="entity.Student">
select sn,sname from student1 where 1=1
<if test="sname!=null">
and sname like '%${sname}%'
</if>
</select>
上面使用了if标签,只有test里面是真值时,才会拼接and sname like ‘%${sname}%’ 这个语句。
2.choose (when, otherwise)
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
<select id="findActive"
resultType="entity.Student">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
3.trim (where, set)
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。
4.foreach
SQL映射文件通过parameterType来指定输入参数类型,如果输入参数是简单类型或一般对象类型,可以直接指定。但是如果输入参数是集合或者数组类型,就需要标签来完成输入输出参数的处理。
<!-- 将集合或数组以对象的形式传入 -->
<select id="findForeach" parameterType="entity.Grade" resultType="entity.Student">
select * from student1
<where>
<if test="sns!=null">
<!-- 使用foreach标签,迭代取出Grade对象中sn集合属性的每个元素 -->
<foreach collection="sns" open="sn in(" close=")" item="sns" separator=",">
#{sns}
</foreach>
</if>
</where>
</select>
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
三、编写程序来实现if、where、foreach标签
数据库表及实体类:
package entity;
public class Student {
private int sn;
private String sname;
private boolean ssex;
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public int getSn() {
return sn;
}
public void setSn(int sn) {
this.sn = sn;
}
public String getsname() {
return sname;
}
public void setsname(String sname) {
this.sname = sname;
}
public boolean getSsex() {
return ssex;
}
public void setSsex(boolean ssex) {
this.ssex = ssex;
}
@Override
public String toString() {
return this.sname+"\t";
}
}
1.实现if标签
定义配置文件mapper.xml
<select id="findif" parameterType="entity.Student" resultType="entity.Student">
select sn,sname from student1 where 1=1
<if test="sname!=null">
and sname like '%${sname}%'
</if>
</select>
定义接口
List<Student> findif(Student sn);
编写测试方法
//实现if标签
public static void testif() throws IOException{
String resource="conf.xml";
Reader reader=Resources.getResourceAsReader(resource);
SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
SqlSession session=sessionFactory.openSession();
StudentDao st=session.getMapper(StudentDao.class);
Student stu=new Student();
stu.setsname("美");
List<Student> students=st.findif(stu);
System.out.println(students);
}
运行测试方法:
2.实现where标签
定义配置文件mapper.xml
<select id="findif" parameterType="entity.Student" resultType="entity.Student">
select sn,sname from student1
<where>
<if test="sname!=null">
and sname like '%${sname}%'
</if>
</where>
</select>
其他的和if标签是一样的
这里就省略运行了
3.实现foreach标签
定义新的实体类Grade
package entity;
import java.util.List;
public class Grade {
private List<Integer> sns;
public List<Integer> getSns() {
return sns;
}
public void setSns(List<Integer> sns) {
this.sns = sns;
}
}
定义配置文件mapper.xml
<!-- 将集合或数组以对象的形式传入 -->
<select id="findForeach" parameterType="entity.Grade" resultType="entity.Student">
select * from student1
<where>
<if test="sns!=null">
<!-- 使用foreach标签,迭代取出Grade对象中sn集合属性的每个元素 -->
<foreach collection="sns" open="sn in(" close=")" item="sns" separator=",">
#{sns}
</foreach>
</if>
</where>
</select>
<!-- 传入List类型集合 -->
<select id="findForeach1" parameterType="java.util.List" resultType="entity.Student">
select * from student1
<where>
<if test="list!=null and list.size>0">
<!-- 使用foreach标签,迭代取出Grade对象中sn集合属性的每个元素 -->
<foreach collection="list" open="sn in(" close=")" item="sns" separator=",">
#{sns}
</foreach>
</if>
</where>
</select>
<!-- 传入简单类型的数组和SQL片段 -->
<select id="findForeach2" parameterType="int[]" resultType="entity.Student">
select * from student1
<where>
<!-- 导入sql片段 -->
<include refid="sql1"/>
<!-- refid属性指向需要导入<sql>标签的id值-->
<!-- 如果<include>的是其他映射文件的SQL片段,则需要加上namespace,比如<include refid="namespace.id"-->
</where>
</select>
<!-- SQL片段 -->
<sql id="sql1">
<if test="array!=null and array.length>0">
<!-- 使用foreach标签,迭代取出Grade对象中sn集合属性的每个元素 -->
<foreach collection="array" open="sn in(" close=")" item="sns" separator=",">
#{sns}
</foreach>
</if>
</sql>
定义接口
package dao;
import java.util.HashMap;
import java.util.List;
import entity.Grade;
import entity.Student;
public interface StudentDao {
List<Student> findForeach(Grade grade);
List<Student> findForeach1(List<Integer> sns);
List<Student> findForeach2(int array[]);
}
编写测试方法
//实现foreach标签,将集合或数组的对象形式传入
public static void testforeach()throws IOException{
String resource="conf.xml";
Reader reader=Resources.getResourceAsReader(resource);
SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
SqlSession session=sessionFactory.openSession();
StudentDao st=session.getMapper(StudentDao.class);
List<Integer> sns=new ArrayList<Integer>();
sns.add(101);
sns.add(102);
sns.add(103);
Grade grade=new Grade();
grade.setSns(sns);
//传入grade对象,该对象包含了List集合类型的属性sns;
List<Student> students=st.findForeach(grade);
System.out.println(students);
}
//实现foreach标签, 传入List的集合
public static void testforeachlist()throws IOException{
String resource="conf.xml";
Reader reader=Resources.getResourceAsReader(resource);
SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
SqlSession session=sessionFactory.openSession();
StudentDao st=session.getMapper(StudentDao.class);
List<Integer> sns=new ArrayList<Integer>();
sns.add(99);
sns.add(102);
sns.add(103);
List<Student> students=st.findForeach1(sns);
System.out.println(students);
}
//实现foreach标签, 传入简单类型的数组
public static void testforeacharray()throws IOException{
int[] array=new int[10];
array[0]=98;
array[1]=99;
String resource="conf.xml";
Reader reader=Resources.getResourceAsReader(resource);
SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
SqlSession session=sessionFactory.openSession();
StudentDao st=session.getMapper(StudentDao.class);
List<Student> students=st.findForeach2(array);
System.out.println(students);
}
运行测试方法
四、简单介绍一下SQL片段
<!-- 传入简单类型的数组和SQL片段 -->
<select id="findForeach2" parameterType="int[]" resultType="entity.Student">
select * from student1
<where>
<!-- 导入sql片段 -->
<include refid="sql1"/>
<!-- refid属性指向需要导入<sql>标签的id值-->
<!-- 如果<include>的是其他映射文件的SQL片段,则需要加上namespace,比如<include refid="namespace.id"-->
</where>
</select>
<!-- SQL片段 -->
<sql id="sql1">
<if test="array!=null and array.length>0">
<!-- 使用foreach标签,迭代取出Grade对象中sn集合属性的每个元素 -->
<foreach collection="array" open="sn in(" close=")" item="sns" separator=",">
#{sns}
</foreach>
</if>
</sql>
上面注解讲的很清楚了,使用的话在写一些复杂的程序就会更方便,可修改性也更好!