目录
动态sql是什么:
根据不同条件拼接 SQL 语句,实现对数据库更准确的操作
Mybatis解决了JDBC的问题:
硬编码、SQL参数固定、代码重复度高、底层的一些技术
而MyBatis的动态sql用法就是解决SQL参数固定的问题
Mybatis 的动态sql用法:
1.映射器配置文件
2.注解
脚本sql、在方法中构建sql、sql语句构造器
一、通过映射器配置文件来实现动态SQL
实现动态sql需要用到的标签
<if>、<choose>、<where>、<set>、<trim>、<foreach>、<bind>、<sql>
if标签
<!-- if 判断 相当于Java中的单条件分支 -->
语法:
<if test="条件">满足条件的语句</if>
例:
<select id="findStudentif" resultType="Student" parameterType="Student">
select * from Student
where 1=1
<!-- test 中填写 OGNL 表达式 对象图 导航语言 属性名 -->
<if test="ssex != null">
and ssex = #{ssex}
</if>
</select>
choose标签
<!--choose 和 when , otherwise 是配套标签 类似于java中的switch,只会选中满足条件的一个-->
语法:
<choose>
<when test=“条件”>满足条件的语句</ when>
<otherwise> 满足其他条件的语句 </otherwise>
</choose>
例:
<select id="findStudentchoose" resultType="Student" parameterType="Student">
select sname,ssex,bithday,classid from Student
where 1=1
<choose>
<when test="sname!=null"> and sname = #{sname} </when>
<when test="ssex!=null"> and ssex = #{ssex} </when>
<when test="birthday!=null"> and birthday = #{birthday} </when>
<when test="classid!=0"> and classid = #{classid} </when>
<otherwise>
and sid=7
</otherwise>
</choose>
</select>
where标签
语法:
<where>
<if test =”条件”> 满足条件的语句 </if>
</where>
特点:
1. 没有任何条件的时候 where标签整体不出现 也不会添加where关键词
2. 将遇到的第一个 and 去掉,没有其他表达式的时候
3. 当有条件的时候 会添加一个 Where 关键词
例:
<select id="findStudentwhere" resultType="Student" parameterType="Student">
select sname,bithday,ssex,classid from Student
<where>
<if test="ssex!=null">
and ssex=#{ssex}
</if>
<if test="classid!=0">
and classid=#{classid}
</if>
</where>
</select>
set标签
语法:
<set>
<if test =”条件”> 满足条件的语句 </if>
</set>
特点:
1. 添加一个set 关键词
2. 将条件中的最后一个, 去掉
例:
<update id="updateStu" parameterType="Student">
update Student
<set>
<if test="sname!=null">
sname=#{sname},
</if>
<if test="birthday!=null">
birthday=#{birthday},
</if>
<if test="ssex!=null">
ssex=#{ssex},
</if>
<if test="classid!=0">
classid=#{classid},
</if>
</set>
<where>
sid=#{sid}
</where>
</update>
trim标签
trim 万能标签 可以代替where标签 set标签
语法:
prefix 开头添加一个 prefixOverrides 开头去掉一个
suffix 结尾添加一个 suffixOverrides 结尾去掉一个
<trim prefix = "" suffixOverrides = "" prefixOverrides = "" suffix = ""></trim>
可以代替set标签
例:
<update id="updateStuTrim" parameterType="Student">
update Student
<trim prefix="set" suffixOverrides=",">
<if test="sname!=null">
sname=#{sname},
</if>
<if test="birthday!=null">
birthday=#{birthday},
</if>
<if test="ssex!=null">
ssex=#{ssex},
</if>
<if test="classid!=0">
classid=#{classid},
</if>
<where>
sid=#{sid}
</where>
</trim>
</update>
可以代替where标签
例:
<select id="findStudentwhere" resultType="Student" parameterType="Student">
select sname,bithday,ssex,classid from Student
<!-- 开头添加一个where 开头去掉一个 and -->
<trim prefix = "where" suffixOverrides = "and">
<if test="ssex!=null">
and ssex=#{ssex}
</if>
<if test="classid!=0">
and classid=#{classid}
</if>
</trim>
</select>
foreach标签
foreach 标签 循环
collection 集合用list 数组用array
item 每个元素的存放起一个变量名
open 开始添加一个
close 结束添加一个
separator 每个元素的分隔符
语法:
<foreach item = "" index = "" collection = "" open = "" separator = "" close = "">
</foreach>
例:
数组
<!-- 查询 foreach array -->
<select id="findStuForeach" resultType="Student">
select * from Student where sid
<foreach collection="array" item="aa" open=" in (" close=")" separator=",">
#{aa}
</foreach>
</select>
集合
<!-- 查询 foreach list -->
<select id="findStuForeachList" resultType="Student">
select * from Student where sid
<foreach collection="list" item="aa" open=" in (" close=")" separator=",">
#{aa}
</foreach>
</select>
bind标签
语法:
<bind name = "" value = "_parameter"></bind>
name
自定义变量的变量名
value
自定义变量的变量值
_parameter
传递进来的参数
模糊查询
<!-- 模糊查询 -->
<select id="findStuBind" resultType="Student">
<!-- 方式一 mybatis 推荐使用 -->
<bind name="bb" value="_parameter+'%'"/>
select * from Student where sname like #{bb}
<!-- 方式二 -->
select * from Student where sname like #{v}"%"
<!-- 方式三 -->
select * from Student where sname like concat(#{v},'%')
<!-- 方式四 直接传 王% -->
select * from Student where sname like #{v}
<!-- 方式五 不推荐
#{} 可以防止SQL注入
${} 字符串替换,不能防止SQL注入
-->
select * from Student where sname like '${v}%'
</select>
sql标签
语法:
<sql id="不能重复"> 需要替代的sql片段 </sql>
调用:
<include refid="定义的sql片段名"></include>
通过调用可以直接当被定义的sql语句使用
例:
<sql id="stusql">select * from Student</sql>
<select id="findStudentif" resultType="Student" parameterType="Student">
<include refid="stusql"></include>
where 1=1
<if test="ssex != null">
and ssex=#{ssex}
</if>
<if test="classid != 0">
and classid=#{classid}
</if>
</select>
二、通过注解来实现动态SQL
注解动态sql有三种
1.脚本SQL
在sql语句中加入<script></script>标签,按照之前sqlmap中的动态sql的样式书写
例:
public interface StudentMapper3 {
//脚本SQL
@Select("<script>"
+ "select * from Student"
+ "<where>"
+ "<if test=\"ssex!=null\"> and ssex = #{ssex} </if>"
+ "<if test=\"classid!=0\"> and classid = #{classid} </if>"
+ "</where>"
+ "</script>")
public List<Student> findAllStudent3(Student s);
}
2.方法中构建SQL
需用到
@SelectProvider
创建动态的 SELECT 语句
@InsertProvider
创建动态的 INSERT 语句
@UpdateProvider
创建动态的 UPDATE 语句
@DeleteProvider
创建动态的 DELETE 语句
这些方法
用法:
1.创建 SQL 语句类
该类包含需要动态生成的SQL 语句;
2.创建Mapper接口类
该类和配置文件的接口文件一样,用来处理数据库操作;
3.利用上述4种方法
将 SQL 语句类和 Mapper 接口类关联,利用方法中的 type 属性和 method 属性;
4.测试验证
编写测试类,测试动态生成的SQL 语句是否准确。
例:
//修改
@UpdateProvider(type = StuLei.class ,method = "updateStudentLei")
public int updateStudent3(Student s);
class StuLei{
//修改
public String updateStudentLei(Student s) {
String sql = "update Student set ";
if(s.getBirthday()!=null) {
sql+="birthday = #{birthday},";
}
if(s.getClassid() != 0 ) {
sql+="classid =#{classid},";
}
if(s.getSname()!=null) {
sql+="sname = #{sname},";
}
if(s.getSsex()!=null) {
sql+="ssex = #{ssex},";
}
sql = sql.substring(0,sql.length()-1);
sql+=" where sid=#{sid}";
return sql;
}
注:这种方法 主要问题是 ,号和 and 的处理
特点:
在接口中定义内部类,来构建需要的动态sql语句,比使用标签的方式结构更加清晰
3.SQL语句构造器
功能:
解决 Java 代码中嵌入 SQL 语句,通过简单地创建一个实例来调用方法生成SQL语句
特点:
没有过多的使用类如 and的连接词
SQL 语句构造器的常用方法
属性名 | 说明 |
SELECT | 开始或插入到 SELECT 子句,可以被多次调用,参数也会添加到 SELECT子句。 |
FROM | 开始或插入到 FROM 子句,可以被多次调用,参数也会添加到 FROM 子句 |
WHERE | 插入新的 WHERE 子句条件,可以多次被调用 |
OR / AND | 使用 OR / AND 来分隔当前的 WHERE 子句的条件 |
DELETE_FROM | 开始一个 delete 语句并指定需要从哪个表删除的表名。 |
INSERT_INTO | 开始一个 insert 语句并指定需要插入数据的表名 |
VALUES | 插入到 insert 语句中。第一个参数是要插入的列名,第二个参数则是该列的值。 |
UPDATE | 开始一个 update 语句并指定需要更新的表名 |
SET | 针对 update 语句,插入到 "set" 列表中 |
注:关键字必须全部大写
例:
public interface StudentMapper {
//删除
@DeleteProvider(type = StuLei.class,method = "gzqDeleteStudent")
public int deleteStudent3(int sid);
//新增
@InsertProvider(type = StuLei.class,method = "gzqAddStudent")
public int addStudent3(Student s);
//查询
@SelectProvider(type = StuLei.class,method = "gzqSelectStudent")
public List<Student> SelectStudent3(Student s);
class StuLei{
//删除
public String gzqDeleteStudent(int sid) {
return new SQL() {
{
DELETE_FROM("student");
WHERE("sid = #{sid}");
}
}.toString();
}
//添加
public String gzqAddStudent(Student s) {
return new SQL() {
{
INSERT_INTO("student");
VALUES("birthday","#{birthday}");
VALUES("sname","#{sname}");
VALUES("ssex","#{ssex}");
VALUES("classid","#{classid}");
}
}.toString();
}
//查询
public String gzqSelectStudent(Student s) {
return new SQL() {
{
SELECT("sid,sname,birthday,ssex,classid");
FROM("student");
if(s.getClassid() != 0) {
WHERE("classid = #{classid}");
}
if(s.getSsex() != null) {
WHERE("ssex = #{ssex}");
}
}
}.toString();
}
}
}