什么是动态SQL?
根据不同条件拼接 SQL 语句,实现对数据库更准确的操作。
为什么会有动态SQL?
因为在我们的网页中,很多功能都是不能写死的,先不说会增加我的工作量,更会影响我们代码的效率。
以下列网站的功能为例,那么多查询条件,一个一个写都要写几十条,更别说把他们组合起来做查询了!!!
如何使用动态SQL?
两种方式:
①映射器XML配置文件
②注解
映射器XML配置文件使用动态SQL
if:单条件分支判断:< if test ="条件"> 满足条件的语句</if>
<select id="findoneStudent" resultMap="stu_class_map" parameterType="student">
<!-- 利用反射对象,让resultType知道我们需要的类型Class.forName("com.mysql.cj.jdbc.Driver")-->
<!-- parameterType=传入参数的类型 ,有传入参数的时候用-->
select * from student where 1=1
<if test="ssex!=null">
and ssex =#{ssex}
<!--如果条件成立则将标签包裹的sql语句拼接,不满足则直接忽略,继续往下执行-->
</if>
<if test="classid!=0">
and classid=#{classid}
</if>
</select>
使用if if时,因为sql语句的拼接,导致每句sql语句前面都要加个连接关键字and,但是这时候如果第一个条件为空时,直接拼接后面带and的语句,就会出现运行错误。可以在where前面加个恒成立1=1,拼接后面的sql;之后所有的sql语句都要加上and;
choose :多条件分支判断,等 同于 java 的 switch 。
<select id="findonechose" resultMap="stu_class_map" parameterType="student">
<include refid="stu_find"></include> where 1=1
<choose>
<when test="ssex!=null">
and ssex=#{ssex}
</when>
<when test="classid!=0">
and classid=#{classid}
</when>
<otherwise>
and sname="奥特曼"
<!--当以上when全不满足则执行otherwise里的代码-->
<!--我很可以有多个,otherwise只能有一个-->
</otherwise>
</choose>
</select>
where:自动拼接where,去and或者or
如果我们第一条的查询条件全部为空时
select * from student where
<if test="ssex!=null">
and ssex =#{ssex}
</if>
<!--如何我们的这段代码不用1=1的这种办法处理,且if里面为null时,我们的sql语句就会出错-->
<!--就会变成这个样子:select * from student where -->
这时候可以用我们的where处理
<select id="findwhere" resultMap="stu_class_map" parameterType="student">
select * from student
<where>
<if test="ssex!=null">
and ssex =#{ssex}
</if>
<if test="classid!=0">
and classid=#{classid}
</if>
</where>
<!--where 只会在至少有一条sql语句被拼接时才会加入,也会自动帮我们去的开头的and,or-->
</select>
set:类似于where,主要是用在新增中 ,会在第一条拼接的语句中自动加上set关键字,并去除,(逗号)
<update id="//updateStudent" parameterType="com.ape.bean.Student">
update student
<set>
<if test="sname!=null">sname=#{sname},</if>
<if test="ssex!=null">ssex=#{ssex},</if>
<if test="birthday!=null">birthday=#{birthday},</if>
<if test="classid!=0">classid=#{classid},</if>
</set>
<where>sid=#{sid}</where>
</update>
<!--在包含的语句前输出一个 set,
然后如果包含的语句是以逗号结束的话将会
把该逗号忽略。有了 set 元素就可以动态的更
新那些修改了的字段-->
trim:万能标签,可代替任意元素标签,进行自定义的拼接,去除;
<trim prefix="(" suffixOverrides="," suffix=")">
<if test="sname!=null">sname,</if>
</trim>
<!--里面有两组标签属性
prefix--开头加上什么,prefixOverrides--开头去掉什么
suffix--结尾加上什么,suffixOverrides--结尾去掉什么-->
<!--修改-->
<update id="updateStudent" parameterType="Student">
update student
<trim prefix="set" suffixOverrides=",">
<if test="sname!=null">sname=#{sname},</if>
<if test="ssex!=null">ssex=#{ssex},</if>
<if test="birthday!=null">birthday=#{birthday},</if>
<if test="classid!=0">classid=#{classid},</if>
</trim>
<where>sid=#{sid}</where>
</update>
<!--新增-->
<insert id="addStudent" parameterType="Student">
insert into student
<trim prefix="(" suffixOverrides="," suffix=")">
<if test="sname!=null">sname,</if>
<if test="ssex!=null">ssex,</if>
<if test="birthday!=null">birthday,</if>
<if test="classid!=0">classid,</if>
</trim>
values
<trim prefix="(" suffixOverrides="," suffix=")">
<if test="sname!=null">#{sname},</if>
<if test="ssex!=null">#{ssex},</if>
<if test="birthday!=null">#{birthday},</if>
<if test="classid!=0">#{classid},</if>
</trim>
</insert>
foreach:循环
<!--foreach循环-->
<foreach collection="list" item="n" open="(" close=")"separator=",">
#{n}
</foreach>
<!--foreach标签里的参数:
collection :传入集合类型list,数组类型:array,或者其他别名
item="n":接参(可写任意)
open="(" 开头加上什么
close=")结尾加上什么
separator=","分隔符是什么;-->
例:
<select id="findbyList" resultMap="stu_class_map" parameterType="Student" >
select * from student where sid in
<foreach collection="list" item="n" open="(" close=")" separator=",">
#{n}
</foreach>
</select>
bind:取别名,在 动态sql里充当处理模糊查询的作用。
<bind name="mh" value="_parameter+'%'"/>
<!--name=要取的名字-->
value=_parameter _parameter就是我们要传入的值,可以在这里做拼接
<!--使用时,只需要填入给标签取的名字-->
select * from student where sname like #{mh}
例:
</select>
<select id="1findBymh" resultMap="stu_class_map" parameterType="String">
<bind name="mh" value="_parameter+'%'"/>
select * from student where sname like #{mh}
</select>
sql片段:不是完整的sql语句
<sql id=""> sql片段,字段</sql>
使用
<include id="sqlid">sqll片段</include>
可以代替写入的sql片段
<sql id="stu_find">
select * from student
</sql>
<select id="findallStudent" resultMap="stu_class_map" >
<include refid="stu_find"></include> left join class on student.classid=class.classid;
</select>
输出之后 sql语句就会变成
select * from student left join class on student.classid=class.classid;
<include refid="stu_find"></include>会代替我们自定义的sql片段
注解中使用动态sql
一,查询
@Select("select * from student ")
public List<Student> findAllStu();
解决多参的问题可以用@Param注解取别名,然后再sql语句中使用别名
二,新增
@Insert("insert into student(sname,ssex,birthday,classid) values(sname,ssex,birthday,classid)")
@Options(keyProperty = "sid", useGeneratedKeys = true)
public int addStudent(Student s);
主键回填问题可以用@Options注解
三,
单表联查,1v1
普通联查发现,主表下面的副标是空值,因为没有做映射;我们在xml文件的时候是用resultMap标签完成的,但是在注释里我们使用Results
@Results({
@Result(column ="classid",property = "classid"),
@Result(column ="classid",one = @One(select ="com.ape.Mapper.BjMapper.findBjbyclassid"),property ="bj")
})
@Select("select * from student")
public List<Student> findStuandClass();
做联查映射关系,column=主表的关联字段,one注解=@one (selec=t获取一个字符串(通过该字符串获取带参数的对象)),
这里需要创建一个接口,写一个获取该对象的方法
select=该接口的类路径.方法
最后赋值给prepery"对象";
prepery对象就是我们要做映射的对象。最终会把coulumn字段映射给prepery对象对应的属性,这时候,主表的映射就没了,需要自己再声明一次
,注释的sql语句没有联查 语法,不能left,join,right;
四,多表联查
一对多:
关键字用many@Many,其他地方跟一对一基本一样
,many注解=@Many (selec=t获取一个字符串(通过该字符串获取带参数的对象)),
用方法写 sql语句:
@UpdateProvider(type = tclei.class,method = "updt")
public int updateTecher(Teacher t);
//type=类映射,写有sql语句的方法的类名,
//methd=类里面的方法名
class tclei{
public String updt(Teacher t) {
//sql方法参数的类型必须跟方法入参的类型一样
String sql="update teacher set ";
if (t.getTname()!=null) {
sql+="tname=#{tname}";
}
if (t.getTname()!=null) {
sql+=",";
}
if (t.getTbirthday()!=null) {
sql+="Tbirthday=#{Tbirthday}";
}
if (t.getTbirthday()!=null) {
sql+=",";
}
if (t.getTsex()!=0) {
sql+="Tsex=#{Tsex}";
}
if (t.getTsex()!=0) {
sql+=",";
}
if (t.getTaddress()!=null) {
sql+="Taddress=#{Taddress}";
}
if (t.getTaddress()!=null) {
sql+=",";
}
if (t.getTemail()!=null) {
sql+="Temail=#{Temail}";
}
//sql=sql.substring(0, sql.length()-1);
sql+=" where tid=#{tid}";
return sql;}
}
SQL方法的过度:构造器,就是SQL方法的升级版
构造器SQL
return new SQL( ) { {
SECECT(可以写多个select,会自动拼接里面的内容)
FROM
if
WHERE
if
} }
多个判断用WHERE隔开,WHERE会自动拼接and
删除
@DeleteProvider(type = DelTea.class,method = "deleteTeacher")
public int deleteTeacher( Teacher t);
//type:类名
//method:方法名
class DelTea{
/返回值必须是String类型
public String deleteTeacher( Teacher t) {
return new SQL() {{
DELETE_FROM("teacher");
if (t.getTid()!=0) {
WHERE("tid=#{tid}");
}else {
WHERE("tid=0");
}
}}.toString();
}
}