一、动态sql语句
什么是动态sql:根据参数的值,判断sql的条件。
MyBatis
的强大特性之一便是它的动态 SQL
,即拼接SQL
字符串。如果你有使用 JDBC
或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL
语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL
这一特性可以彻底摆脱这种痛苦。
通常使用动态 SQL
不可能是独立的一部分,MyBati
s 当然使用一种强大的动态 SQL
语言来改进这种情形,这种语言可以被用在任意的 SQL
映射语句中。
动态 SQL
元素和使用 JSTL
或其他类似基于 XML
的文本处理器相似。在 MyBatis
之前的版本中,有很多的元素需要来了解。MyBatis 3
大大提升了它们,现在用不到原先一半的元素就可以了。MyBatis
采用功能强大的基于 OGNL
的表达式来消除其他元素。
mybatis中的动态sql标签
1、if标签--单条件判断
可以通过条件判断,动态拼接sql
if标签一般用于非空验证,如上例,若id为空,if标签里的代码,将不会执行,反之,则会执行。
<!--因为如果id 或者 name 都为null 那么where后面的sql语句就会被隐藏,这样sql语句就会错所有加上1=1-->
<select id="find_teacher" resultType="com.gsh.entity.Teacher">
select * from teacher where 1=1
/*test里是条件,如果条件成立那么if内的内容会显示否则不显示*/
<if test="id!=null and id!=''">
and id=#{id}
</if>
<if test="name!=null and name!=''">
and name=#{name}
</if>
</select>
2、choose--多条件分支判断
<!--choose 多分支判断相当于switch when是里边的case -->
<select id="find_teacher" resultType="com.gsh.entity.Teacher">
select * from teacher where 1=1
<choose>
<when test="id!=null and id!=''">
and id=#{id}
</when>
<when test="name!=null and name!=''">
and name=#{name}
</when>
<otherwise>
</otherwise>
</choose>
</select>
3、where标签
我们观察到上面的sql都加了 where 1=1 ,如果不使用where 1=1 那么你的动态sql可能会出错。 我们能不能不加where 1=1呢! 可以 那么我们就可以使用where标签,作用:可以自动为你添加where关键字,并且可以帮你去除第一个and |or
where一般和if结合使用,根据参数值动态拼接sql
1.当需要拼接条件的时候,会自动拼接where关键字
2.自动去除第一个条件前面的and关键字
注:where标签会根据情况自动过滤掉前面的and
where 元素知道只有在一个以上的if条件有值的情况下才去插入“WHERE”子句。而且,若最后的内容是“AND”或“OR”开头的,where 元素也知道如何将他们去除。
如果 where 元素没有按正常套路出牌,我们还是可以通过自定义 trim 元素来定制我们想要的功能。比如,和 where 元素等价的自定义 trim 元素为:
trim 可以更新内容,也可以替换内容
<!--where-->
<select id="find_teacher" resultType="com.gsh.entity.Teacher">
select *from teacher
<where>
<if test="id!=null and id!=''">
and id=#{id}
</if>
<if test="name!=null and name!=''">
and name=#{name}
</if>
</where>
</select>
4、foreach标签
foreach
标签可迭代任何对象(如数组、集合(list,set,map)等)和任何的字典或者数组对象传递给foreach
作为集合参数,当使用可迭代对象或者数组时,index
是当前迭代的次数,item
的值是本次迭代获取的元素。当使用字典(或者Map.Entry
对象的集合)时,index
是键,item
是值。collection
标签可以填('list','array','map')
。
foreach
元素的属性主要有 item,index,collection,open,separator,close
。
collection:指定要循环的目标数据的类型,数组(array) list集合(list)
item:存储遍历的某个数据对象
open:拼接的字符串的前缀
close:拼接的字符串的后缀
separator:拼接内容的分隔符
使用foreach批量查询:
<mapper namespace="com.gsh.dao.UserDao">
<select id="findAll" resultType="com.gsh.entity.User">
select *from user where id in
//目标数据类型 赋值给的元素 以什么开始以什么结束 用什么分割
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
</mapper>
使用foreach批量删除:
<delete id="deleAll">
delete from user where id in
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
使用foreach批量添加
<insert id="addAll">
insert into user(username,password,name) values
<foreach collection="list" item="u" separator=",">
(#{u.username},#{u.password},#{u.name})
</foreach>
</insert>
5.sql片段
在执行查询语句时不建议使用select *, 建议把查询的列写出。
我们可以把所有的列定义到sql标签中
//定义的sql列 id可以理解为使用时的名字
<sql id="sql_stu">
stu_id,stu_name,stu_age,c_id,c_name
</sql>
<select id="find_all" resultMap="stuMap">
//在这里我们就可以通过 include标签使用我们定义的sql
select <include refid="sql_stu"/>from tb_student s join tb_class c on s.class_id=c.c_id where stu_id=#{id};
</select>
6.mybatis处理特殊字符
在xml文件中尽量避免写大于,小于,大于等于,小于等于 &
两种方式
第一种使用转义字符
第二种使用<![CDATA[sql]]>
<![CDATA[
含有特殊符号的代码
]]>
<select id="find_age" resultType="com.gsh.entity.Student">
<![CDATA[select * from student where age >#{min} and age <#{max}]]>
</select>
7、mybatis完成模糊查询
一共有两种方案可以完成模糊查询
第一种:${}
${}: 用字符串拼接的方式,拼接sql语句。当方法参数只有一个值的时候,
必须写${value}。不安全,会导致sql注入
<select id="select_like" resultType="com.gsh.entity.student">
select * from student where name like '%${name}%'
</select>
第二种:使用字符串函数 完成拼接 concat
<select id="select_like" resultType="com.gsh.entity.Student">
select * from student where name like concat('%',#{name},'%')
</select>
通过观察: 发现使用${}实际上是字符串拼接,它不能防止sql注入, 而#{}它是预编译,它可以防止sql注入问题,#{}实际使用的PreparedStatement.
8、多表联查
多对一的关系,一个学生只属于一个班级,一个班级可以拥有多名学生,学生与班级的关系就属于多对一。
案例:通过学生的学号查询出学生的信息和学生所在班级的信息
第一步:在创建班级实体类,将班级信息作为属性封装在班级类中
第二步:在学生实体类属性中封装一个班级属性
public class Student {
private int id;
private String name;
private int age;
private int cid;
//班级属性
private Clazz clazz;
}
第三步:在学生dao中封装对应的方法
第四步:在学生的StudentMapper.xml文件中使用resultMap标签与association标签完成多表联查
使用association
标签来解决一对一的关联查询,association
标签可用的属性如下:
property:表示属性名
javaType:表示属性的类型(该属性名对应的数据类型)
<resultMap id="stuMap" type="com.gsh.entity.Student">
<id column="stu_id" property="id"/>
<result column="stu_name" property="name"/>
<result column="stu_age" property="age"/>
<result column="class_id" property="cid"/>
//association表示一对一的关系,它是一的一方
<association property="clazz" column="c_id" javaType="com.gsh.entity.Clazz">
<id column="c_id" property="cid"/>
<result column="c_name" property="cname"/>
</association>
</resultMap>
<sql id="sql_stu">
stu_id,stu_name,stu_age,c_id,c_name
</sql>
<select id="find_all" resultMap="stuMap">
select <include refid="sql_stu"/>from tb_student s join tb_class c on s.class_id=c.c_id where stu_id=#{id};
</select>