Java框架myBatis(二)

一、#{}和${}的区别

#{}所采取的时占位符方式(底层是预编译模式),与JDBC中的?方式相同,传参更加方便安全 ,防止了sql注入。当我们需要向sql传值,使用#{};

${}是将内容直接拼接到sql语句中(底层是字符串拼接),一般不用与sql传值。一般用于向sql中动态传递列名 并且在接口处需要通过@Param()进行绑定。其一般用于传列名,可以用于按照某一列排序(select * from表 order by ${列名} desc/asc),或是不确定列的查询(select ${列名} from 表)等操作

区别:

1、底层实现不同: #{}底层是预编译功能,防止sql注入,更加安全

                                ${}}底层是字符串拼接,直接将值拼接到sql中

2、使用场景不同: #{}一般用于向sql中的列传值

                                ${}一般用于向sql中动态传递列名,例如排序时后面列名可改变 

                                                                                        例如select后面的列名可以自由选择

 

二、多表关联查询

 将student表和major表关联         

package com.wbc.myBatisProject.model;

public class Student {
    private int id;
    private String name;
    private int num;
    private String gender;
    private Major major;//建议在学生中关联专业,将专业相关的属性放在major
    //private int id; private String name 需学生类重新把关联的专业属性创建了一遍,太过冗余
    public Major getMajor() {
        return major;
    }

    public void setMajor(Major major) {
        this.major = major;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}
package com.wbc.myBatisProject.model;

import java.util.List;

public class Major {
    private int id;
    private String name;
    private List<Student> studentList;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

studentDao层

package com.wbc.myBatisProject.dao;

import com.wbc.myBatisProject.model.Student;

public interface StudentDao {
    Student getStudentById(int id);
}

student映射

(1)直接多表关联查询出需要的数据

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace需要和接口路径对应-->
<mapper namespace="com.wbc.myBatisProject.dao.StudentDao">
<!--    对关联查询道德学生信息进行自定义封装-->
    <resultMap id="studentMap" type="Student">
        <id column="id" property="id"></id>
        <result column="num" property="num"></result>
        <result column="name" property="name"></result>
        <result column="gender" property="gender"></result>
<!--        映射关联数据 专业名称  首先会创建一个major对象 然后将major对象封装到student对象-->
        <association property="major" javaType="major">
            <result column="mname" property="name"></result>
        </association>
    </resultMap>
    <select id="getStudentById" resultMap="studentMap" >
        select s.id,s.num,s.name,s.gender,m.name mname from student s inner join major m on s.majorid = m.id where s.id = #{id}
    </select>
</mapper>

        在关联查询中通过select标签的resultMap属性绑定结果映射resultMap标签的id属性

        resultMap标签的type属性绑定返回的类型

        id标签的column属性绑定查询的主键 property属性是返回类型Student内部的属性

        result标签用于绑定主键之外的查询值 column和property与id类似

        association标签用于映射关联数据(查询关联表中的数据)property绑定关联的表 javaType表示关联的类,内部通过result标签绑定数据

(2) 先查询主表,再查询关联表

<resultMap id="studentMap1" type="Student">
        <id column="id" property="id"></id>
        <result column="num" property="num"></result>
        <result column="name" property="name"></result>
        <result column="gender" property="gender"></result>
        <association property="major" javaType="Major" select="findMajorById" column="majorid">

        </association>
    </resultMap>
    <select id="getStudentById1" resultMap="studentMap1">
        select id,num,name,gender,majorid from student where id = #{id}
    </select>
<!--    嵌套查询学生关联的专业-->
    <select id="findMajorById" resultType="Major">
        select name from major where id = #{majorid}
    </select>

        通过写两个select标签分别查询student表和major表,association标签中的select属性与查询关联表的select标签中的id属性进行绑定 column与主表中查询出的需要在关联表使用的列进行绑定。

        select中的 resultType属性确定返回类型

(3)查询一对多关联信息

假设我们需要查询专业和专业内选择该专业的所有学生

正常查询需要两个major对象接收结果,而myBatis为我们提供了collection标签为我们解决了这个问题

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace需要和接口路径对应-->
<mapper namespace="com.wbc.myBatisProject.dao.MajorDao">

<!--    查询专业时,可以将多个学生封装到一个集合中-->
    <resultMap id="majorMap" type="major">
        <id column="id" property="id"></id>
        <result property="name" column="name"></result>
<!--        将查询到的多条结果封装到集合-->
        <collection property="studentList" javaType="list" ofType="student">
            <result column="num" property="num"></result>
            <result column="sname" property="name"></result>
        </collection>
    </resultMap>
    <select id="findMajorById" resultMap="majorMap" >
        select m.id,m.name,s.num,s.name sname from major m inner join student s on m.id = s.majorid where m.id = #{id}
    </select>
</mapper>

通过在major类中添加集合属性来接收多个结果

 collection标签中的property属性对应着类中的集合名称,javaType对应着返回的集合类型,offType对应着集合中的泛型

在collection内部通过result标签接收查询结果

(4)一对多关联查询的两次查询

当我们进行分页操作时,一次操作会出现list集合中的数量和实际sql查询数量不一致的情况,这时候需要分两次查询

<!--分两次查询-->
    <resultMap id="majorMap1" type="major">
        <id column="id" property="id"></id>
        <result property="name" column="name"></result>
        <!--        将查询到的多条结果封装到集合-->
        <collection property="studentList" javaType="list" ofType="student" select="findStudents" column="id">
        </collection>
    </resultMap>
    <select id="findMajors1"  resultMap="majorMap1">
        select id,name from major
    </select>
    <select id="findStudents"  resultMap="majorMap1">
        select id,name from student where majorid = #{id}
    </select>
</mapper>

通过在collecetion标签中添加select属性和column属性绑定第二条sql语句并传入参数

 (5)注释方式执行sql

 @Insert("insert into major(naem)values(#{name})")
    void insertMajor(Major major);

    @Select("select id , name from major")
    List<Major> majors();

当sql语句简单时,可以使用注解标签添加sql,但复杂的sql不建议使用注解

一般适用于单张表的简单增删改查 

三、动态sql

动态sql是myBatis一个强大的功能,避免了根据不同条件需要拼接不同字符串的痛苦过程

以Teacher类为例

package com.wbc.myBatisProject.model;

import org.apache.ibatis.annotations.Insert;

public class Teacher {
    private Integer id;
    private String name;
    private Integer num;
    private String gender;

    public Integer getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}
package com.wbc.myBatisProject.dao;

import com.wbc.myBatisProject.model.Teacher;

import java.util.List;

public interface TeacherDao {
    List<Teacher> teachers(Teacher teacher);
}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace需要和接口路径对应-->
<mapper namespace="com.wbc.myBatisProject.dao.TeacherDao">

    <!--
        动态SQL
            可以在sql中添加逻辑判断
            <if>标签中的test属性条件如果返回为true,则执行if标签体,不成立则不执行
            <where>标签 当标签内的if语句有条件成立时,就会动态添加where关键字,如果where关键字后紧跟着的关键字(例如and,or),就会自动删除以保证sql语句语法错误
    -->
    <select id="teachers" resultType="Teacher" >
        select * from teacher
            <where>
                <if test="num!=null">
                    num = #{num}
                </if>
                <if test="name!=null">
                    and name = #{name}
                </if>
                <if test="gender!=null">
                    and gender = #{gender}
                </if>
            </where>

    </select>
</mapper>


        动态SQL可以在sql中添加逻辑判

        <if>标签

标签中的test属性条件如果返回为true,则执行if标签体,不成立则不执行

        <where>标签

当标签内的if语句有条件成立时,就会动态添加where关键字,如果where关键字后紧跟着的关键字(例如and,or),就会自动删除以保证sql语句语法错误

        <trim>标签

同样的,用<trim>同样可以完成这项操作,tirm的功能更加强大,灵活度更高

<!--
    <trim> 标签 当条件判断成立时,可以自定义前缀关键字和后缀关键字
    prefix="where" 添加前缀关键字
    prefixOverrides="and | or"覆盖指定后缀关键字
-->
<select id="teachers" resultType="Teacher" >
        select * from teacher
            <trim prefix="where" prefixOverrides="and | or">
                <if test="num!=null">
                    num = #{num}
                </if>
                <if test="name!=null">
                    or name = #{name}
                </if>
                <if test="gender!=null">
                    and gender = #{gender}
                </if>
            </trim>

    </select>

<choose>标签

并且 if也可以用choose标签替换 choose标签的使用于java中的choose类似

<when>标签

<otherwise>标签        

当我们使用choose标签时,内部必须使用when标签做条件判断,when标签的test属性用于判断条件。otherwise标签相当于else,在choose标签内部至多可以写一个otherwise标签,也可以不写otherwise标签

<!--
    otherwise相当于else 可以不写,最多可以写一个
    但是当使用<choose>标签时,必须在标签体内写<when>表签 when标签的test属性用于判断条件是否成立
-->
    <select id="teachers" resultType="Teacher" >
        select * from teacher
            <trim prefix="where" prefixOverrides="and | or">
                <choose >
                    <when test="name!=null">
                        name=#{name}
                    </when>
                    <otherwise>
                        name="李老师"
                    </otherwise>
                </choose>
            </trim>

    </select>

  <set>标签

当我们需要用if等选择标签进行列名拼接时,会出现最后一位仍有逗号的情况。原因是如果最后一位没有达成if标签中的条件时,其他位作为最后一位会将原本的逗号带着拼接进sql语句。而set标签就可以解决这一问题,它可以把最后一个逗号去掉

<!--set去逗号-->
    <!--当每次拼接后需要逗号连接,但有可能前面的不符合条件不执行 set标签可以把最后一个,删除,以保证语法正确-->
    <!--当然set标签也可以用item代替-->
    <update id="updateTeacher" parameterType="Teacher" >
        update teacher
           <set>
               <if test="num!=null">
                   num=#{num},
               </if>
               <if test="name!=null">
                   name=#{name},
               </if>
               <if test="gender!=null">
                   gender=#{gender},
               </if>
           </set>
        <where>
            id = #{id}
        </where>
    </update>

      测试

 @Test
    public void test1(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        TeacherDao teacherDao = sqlSession.getMapper(TeacherDao.class);
        Teacher teacher = new Teacher();
        teacher.setId(1);
        teacher.setName("陈老师");
        teacher.setNum(1004);
        teacherDao.updateTeacher(teacher);
        sqlSession.commit();
        sqlSession.close();
    }

 传入的参数teacher没有调用setGender方法设置gender,在调用gender时gender=null不符合if条件,此时name是set标签中最后的需要拼接的元素,此时set自动将逗号去掉了,保障了语法的正确性 

<foreach>标签 

foreach标签的作用是循环

此处我们假设两个示例

第一个是我们的批量删除,如果我们每次删除时前端请求一次,将id发送给后端,后端再调用sql删除,是否太过麻烦。有了foreach之后,我们可以一次性拿到所有要删除事物的id发给后端,后端将其传入数组或List集合,将其传入dao层映射的方法中,通过foreach标签循环调用sql,完成批量删除的操作

假设1、2、3是需要批量删除的老师的id 通过数组传输

 @Test
    public void test2(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        TeacherDao teacherDao = sqlSession.getMapper(TeacherDao.class);
       teacherDao.deleteTeacher(new Integer[]{1,2,3});
        sqlSession.commit();
        sqlSession.close();
    }

dao层接口通过此方法映射给对应的Mapper 

List<Teacher> findTeacher(List<String> columns);

从而调用这条sql

 <!-- foreach标签循环 collection是传参类型 传入数组时等于array 传入List则等于list-->
    <!--item 表示增强for循环中的每次循环取出的值  open是循环开始时需要拼接的 separator是传入参数后拼接的  close是结束时需要拼接的-->
    <delete id="deleteTeacher">
        delete from teacher  where id in
               <foreach item="id" collection="array" open="(" separator="," close=")">
                   #{id}
               </foreach>
    </delete>

foreach 标签中,collection="传入数据的类型"(数组填array,集合填list)

                           item=”每次从数组或集合中取出的数据的别名“(随便起一个名字)

                           open=”循环开始前需要拼接的符号“

                           separator=”每次循环传入数据后需要拼接的符号“

                            close=”循环结束需要拼接的符号“                           

第二个例子是我们在前端通过标签筛选想要看到的东西,前端拿到这些标签传入后端,后端再根据传入的数据调取数据库数据返回前端,也需要我们通过foreach循环拼接列名

 @Test
    public void test3(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        TeacherDao teacherDao = sqlSession.getMapper(TeacherDao.class);
        List<String> columns = new ArrayList<>();
        columns.add("num");
        columns.add("name");
        columns.add("gender");
        teacherDao.findTeacher(columns);
        sqlSession.commit();
        sqlSession.close();
    }

 这里由于sql语句不需要在循环前拼接,所以没有写 open属性和close属性

由于传入的是列名,所以不可以用#{xxx}传输,需要用¥{xxx}传输

<select id="findTeacher" resultType="Teacher">
        select
            <foreach collection="list" item="column" separator=",">
                ${column}
            </foreach>
            from teacher
    </select>

自此,全部的动态sql学习完毕

  • 13
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北京最后的深情

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值