一、动态sql
1.1 sql片段
在书写sql语句的查询时,不推荐大家用 * 号,建议大家把想要查询出来的列都写出。具体的写法如下:(1)写sql标签 (2)在sql语句中引入sql片段
1.2 set标签
set标签多配合if标签一起使用,一般都是用在修改语句。例子:如果传递的参数值为null,不修改该列的值。
set标签可以帮我们生成sql内的关键字---set,并且可以动态的帮我们去除最后一个逗号。代码如下:
测试代码如下:我们传的参数为一个student实体类,里面的属性有name,age,cid和一个ACalss(自定义的)类的aclass,我们只需要关系我们要用到的name,age和cid即可。
@Test
public void testUpdateBySet() throws Exception{
SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis.xml")).openSession();
StudentDao studentDao = session.getMapper(StudentDao.class);
Student student = new Student(1,"lrs",45,2,null);
//Student student1 = new Student(2,"",18,null,null);
int i = studentDao.updateBySet(student);
System.out.println(i);
session.commit();
session.close();
}
我们需要修改的值为name,age,cid,这些都不为空, 那么动态sql语句就应该变成:
可以发现,set标签会自动帮我们去除最后cid处的逗号。
1.3 foreach标签
循环标签,可以帮助我们处理一些动态的批量任务,例如批量添加,批量查询,批量删除等等。我们可以传入一个数组或者一个list集合,然后通过foreach标签将集合内的条件一个一个的放入我们的sql语句从而实现动态的批量处理效果。
foreach标签内属性:
- collection:类型 如果你使用的为数组array 如果你使用的为集合 那么就用list
- item:数组中每个元素赋值的变量名
- open: 以谁开始
- close:以谁结束
- separator:分割符
用到的数据库的表如图。下面给大家列举三个例子:
(1)根据id批量查询学生信息
StudentDao:
StudentMapper:
<resultMap id="stuMap" type="com.lrs.entity.Student">
<id column="stu_id" property="id"/>
<result column="stu_name" property="name"/>
<result column="stu_age" property="age"/>
</resultMap>
<sql id="stu">
stu_id,stu_name,stu_age,cid
</sql>
<select id="selectByFor" resultMap="stuMap">
select
<include refid="stu"/>
from student where stu_id in
<foreach collection="array" item="forEachIds" separator="," open="(" close=")">
#{forEachIds}
</foreach>
</select>
(2)根据id批量删除
StudentDao:
StudentMapper:
<delete id="deleteBuFor">
delete from student where stu_id in
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
(3)批量添加学生信息
这里我们传入的参数可以换成集合类型------List<Student>集合。集合里面装的都是Student对象类型的数据。这样才能将要添加的学生的信息传入到sql中。
StudentDao:
StudentMapper:注意,我们要想调用list集合内的Student对象的属性,调用的写法应该为“Xxx(item名称).xxx(属性名)”。同样自定义对象类型的数组也应该这样调用属性。
<insert id="insertByFor">
insert into student values
<foreach collection="list" item="stu" separator=",">
(null,#{stu.name},#{stu.age},#{stu.cid})
</foreach>
</insert>
二、映射文件特殊字符的处理
在Mapper中写我们的sql语句中,会遇到一些特殊的字符,他会与我们的sql代码会产生冲突,例如我们sql中写这样的语句:
可以看到我们的小于号,就是一种特殊字符。那么我们该如何处理这种问题?
有两种方法可以解决。
第一种:使用转义符。java中有这些特殊字符的转义符。
第二种:用 <![CDATA[sql语句]]> 方法 注意这种方法不能括住我们的标签(例如include标签),我们可以在需要用到的地方使用这个方法,没必要整个sql语句都套入在内。
三、模糊查询
模糊查询的sql语句:
select * from 表名 where 列名 like '%a%'
有两种方法可以实现这种拼接。
(1)使用字符串函数 完成拼接 -----concat(这属于sql基础的知识点)
<select id="selectByLike" resultMap="stuMap">
select <include refid="stu"/> from student where stu_name like concat('%',#{name},'%')
</select>
(2) 使用${ } 代替。 这种方式实际上是字符串的拼接,他并不能防止sql注入问题,而我们之前用的#{ }就相当于预编译,可以防止sql注入问题。所有这种方式不推荐使用,所谓防君子不防小人。
<select id="selectByLike" resultMap="stuMap">
select <include refid="stu"/> from student where stu_name like '%${name}%'
</select>
四、联表查询
例子:根据id查询学生信息并包括该学生所在的班级信息。
需要用的表:我们需要从多的一方来查询一的一方。这里学生表就相当于多的一方,班级表就相当于1的一方。
sql语句:
select * from tb_stu s join tb_class c on s.class_id=c.cid where stu_id= xxx
实现方式一:
首先在我们的Student实体类种(相当于多的一方)加入我们AClass类型(一的一方)的属性
package com.lrs.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @作者:刘壬杉
* @创建时间 2022/6/3
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private Integer id;
private String name;
private Integer age;
private Integer cid;
private AClass aClass; //AClass类型的属性。
}
StudentDao:
StudentMapper: 重点:resultMap标签内的association标签 :表示 一 的一方。property:表示属性名(就是我们实体类种的aclass属性)。javaType:表示该属性名对应的数据类型。
<resultMap id="all" type="com.lrs.entity.Student">
<id column="stu_id" property="id"/>
<result column="stu_name" property="name"/>
<result column="stu_age" property="age"/>
<result column="c_id" property="cid"/>
<association property="aClass" javaType="com.lrs.entity.AClass">
<id column="cid" property="cid"/>
<result column="cname" property="cname"/>
</association>
</resultMap>
<sql id="allClass">
stu_id,stu_name,stu_age,s.cid c_id,c.cid,cname
</sql>
<select id="selectClassById" resultMap="all">
select <include refid="allClass"/> from student s join class c on s.cid = c.cid where stu_id=#{id}
</select>
实现方式二:
map封装(不推荐这种方式)。用这种方式封装我们查询到的数据,就不需要改动我们的实体类,也不用关心其属性内的映射关系。
StudentDao:
StudentMapper:
<select id="selectClassById2" resultType="java.util.Map">
select <include refid="allClass"/> from student s join class c on s.cid = c.cid where stu_id=#{id}
</select>
需要避免的问题:两个表的列名应该尽量避免相同,如果相同,需要起别名来区别。resultMap中的标签内的column属性应该与你起了别名后的列名相同。Map本身也是无序不重复的,我们的属性名也就是map中的key值也需要保证不能相同。
体会:使用mybatis我们需要做的事情就是处理好查询到的结果与返回值(一般是你得实体类或实体类组成的集合)的属性相对应(resultMap标签)。其他的内容与我们学习JDBC+Dao整合时大致相同。所以难点就在于将返回的内容处理好,其他的一些包括sql语句标签和动态sql标签都是帮助我们书写sql语句的,基础的sql部分的知识点需要掌握。框架的好处就是帮我们简化流程,不要把他想的很复杂。