Mybatis從淺入深-Plus(IDEA版通俗易懂)

每個成功者都有一個開始。敢於開始,才能找到成功的路。你好,我是夢陽辰!期待與你相遇!java

Mybatis從淺入深(IDEA版通俗易懂)算法

01.使用註解開發

引入:
你們以前都學過面向對象編程,也學習過接口,但在真正的開發中,不少時候咱們會選擇面向接口編程spring

根本緣由∶解耦,可拓展,提升複用,分層開發中,上層不用管具體的實現,你們都遵照共同的標準,使得開發變得容易,規範性更好sql

在一個面向對象的系統中,系統的各類功能是由許許多多的不一樣對象協做完成的。在這種狀況下,各個對象內部是如何實現本身的,對系統設計人員來說就不那麼重要了;數據庫

而各個對象之間的協做關係則成爲系統設計的關鍵。小到不一樣類之間的通訊,大到各模塊之間的交互,在系統設計之初都是要着重考慮的,這也是系統設計的主要工做內容。面向接口編程就是指按照這種思想來編程。
關於接口的理解apache

接口從更深層次的理解,應是定義(規範,約束)與實現(名實分離的原則)的分離。-接口的自己反映了系統設計人員對系統的抽象理解。編程

接口應有兩類:緩存

第一類是對一個個體的抽象,它可對應爲一個抽象體(abstract class);安全

第二類是對一個個體某一方面的抽象,即造成一個抽象面(interface) ;session

一個體有可能有多個抽象面。抽象體與抽象面是有區別的。

三個面向的區別:

面向對象是指,咱們考慮問題時,以對象爲單位,考慮它的屬性及方法.

面向過程是指,咱們考慮問題時,以一個具體的流程(事務過程)爲單位,考慮它的實現.

接口設計與非接口設計是針對複用技術而言的,與面向對象(過程)不是一個問題.更多的體現就是對系統總體的架構

使用註解開發:
它們映射的語句能夠不用 XML 來配置,而可使用 Java 註解來配置。好比,上面的 XML 示例能夠被替換成以下的配置:

package org.mybatis.example;public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  Blog selectBlog(int id);}

使用註解來映射簡單語句會使代碼顯得更加簡潔,但對於稍微複雜一點的語句,Java 註解不只力不從心,還會讓你本就複雜的 SQL 語句更加混亂不堪。 所以,若是你須要作一些很複雜的操做,最好用 XML 來映射語句。

選擇何種方式來配置映射,以及認爲是否應該要統一映射語句定義的形式,徹底取決於你和你的團隊。 換句話說,永遠不要拘泥於一種方式,你能夠很輕鬆的在基於註解和 XML 的語句映射方式間自由移植和切換。

1.註解在接口上實現

**
 * 接口操做user表 */public interface UserMapper {

    @Select("select * from user")
   List<User> selectUser();}

2.須要在覈心配置文件中綁定接口。

<!--綁定接口-->
    <mappers>
        <mapper class="com.mengyangchen.dao.UserMapper"/>
    </mappers>

測試:

 @Test
    public void test(){
        //1.獲取SqlSession對象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //方式一:getMapper
        //2.執行sql,獲取sql,面向接口編程,獲取UserMapper接口(之前是實現接口的實現類,如今是配置文件)
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.selectUser();


        /*String sqlId = "com.mengyangchen.dao.UserDao"+"."+"selectUser";
        List<User> userList = sqlSession.selectList(sqlId);*/
        for(User user:userList){
            System.out.println(user);
        }

        //3.關閉SqlSession
        sqlSession.close();
    }

本質:反射機制實現

底層:動態代理。

Mybatis詳細的執行流程
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

多debug,多看底層源碼。

註解完成增刪改查

接口:

 //方法存在多個參數,全部的參數前面必須加上@Param("id")註解,引用對象不須要寫
    @Select("select * from user where id=#{id}")
    User selectUserById(@Param("id") int id);

    @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")
    int insertUser(User user);

測試:

 @Test
    public void selectUserById(){
        //1.獲取SqlSession對象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //方式一:getMapper
        //2.執行sql,獲取sql,面向接口編程,獲取UserMapper接口(之前是實現接口的實現類,如今是配置文件)
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.selectUserById(1);
        System.out.println(user);
        sqlSession.close();
    }

    @Test
    public void insertUser(){
        //1.獲取SqlSession對象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //方式一:getMapper
        //2.執行sql,獲取sql,面向接口編程,獲取UserMapper接口(之前是實現接口的實現類,如今是配置文件)
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int num = mapper.insertUser(new User(3,"meng","123456"));
        if(num>0){
            System.out.println("插入成功!");
        }
        sqlSession.commit();
        sqlSession.close();
    }

#{},${}的區別
#{}能夠防止sql注入。

02.Lombok

Lombok項目是一個Java庫,它會自動插入您的編輯器和構建工具中,從而使您的Java更加生動有趣。
永遠不要再寫另外一個getter或equals方法,帶有一個註釋的您的類有一個功能全面的生成器,自動化您的日誌記錄變量等等。

Lombok是一款Java開發插件,使得Java開發者能夠經過其定義的一些註解來消除業務工程中冗長和繁瑣的代碼,尤爲對於簡單的Java模型對象(POJO)。在開發環境中使用Lombok插件後,Java開發人員能夠節省出重複構建,諸如hashCode和equals這樣的方法以及各類業務對象模型的accessor和ToString等方法的大量時間。對於這些方法,它可以在編譯源代碼期間自動幫咱們生成這些方法,並無如反射那樣下降程序的性能。

使用步驟:
1.在idea中安裝Lombok插件
打開setting
在這裏插入圖片描述

2.在項目中導入Lombokjar包

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope></dependency>

Lombok含有的註解:

@Getter and @Setter@FieldNameConstants@ToString@EqualsAndHashCode@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog@Data@Builder@SuperBuilder@Singular@Delegate@Value@Accessors@Wither@With@SneakyThrows@val@var

結果:

import lombok.Data;@Datapublic class User {
    private Integer id;
    private String name;
    private String password;
    }

在這裏插入圖片描述
自動幫咱們寫了getter或equals等方法。

@Data:無參構造,get,set,toString,hashcode,equals

無參和全部參數:
在這裏插入圖片描述
注意:瞭解便可。

03.多對一處理

在這裏插入圖片描述
多個學生,對應一個老師。
對於學生而言:關聯…
多個學生關聯一個老師(多對一)
在這裏插入圖片描述

對於老師而言:
集合

一個老師,有不少學生(一對多)

多對一:
實體類

public class Student {
    private Integer id;
    private String name;

    //學生須要關聯一個老師
    private Teacher teacher;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", teacher=" + teacher +
                '}';
    }}
public class Teacher {
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }}

環境搭建:
1.新建實體類Teacher,Student
2.創建Mapper接口
3.創建Mapper.xml文件
4.在覈心配置文件中綁定註冊咱們的mapper接口或者文件。
5.測試是否成功。

public interface TeacherMapper {
    @Select("select * from teacher where id=#{tid}")
    Teacher selectTeacherById(@Param("tid") int id);}
<mappers>
    <mapper class="com.mengyangchen.dao.TeacherMapper"/>
    <mapper class="com.mengyangchen.dao.StudentMapper"/></mappers>
public class MyTest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher =  mapper.selectTeacherById(1);
        System.out.println(teacher);
        sqlSession.close();
    }}

在這裏插入圖片描述
嵌套查詢(按照查詢嵌套處理)(子查詢):
select語句的嵌套。
這裏測試的時候出現異常:
org.apache.ibatis.binding.bindingexception: invalid bound statement (not found)

問題出在:我在建立包的時候
在這裏插入圖片描述
採用的是:

com.mengyangchen.dao

改成一個一個的建立便可。

<?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"><!--綁定一個對應的Dao/Mapper接口--><!--之前是寫一個類實現Dao接口,如今綁定便可--><mapper namespace="com.mengyangchen.dao.StudentMapper"><!--sql語句嵌套思路:    1.查詢全部的學生信息    2.根據查詢出來的學生的tid,尋找對應的老師-->
    <resultMap id="studentTeacher" type="student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--複雜的屬性,咱們須要單獨處理 對象association 集合collection-->
        <association property="teacher" column="tid" javaType="Teacher" select="selectTeacherById"/>
    </resultMap><select id="selectStudentInfo" resultMap="studentTeacher">
   select * from student</select>

    <select id="selectTeacherById" resultType="teacher">
        select * from teacher where id=#{id}
    </select></mapper>

結果:
在這裏插入圖片描述

聯表查詢(按照結果嵌套處理):
在這裏插入圖片描述

<?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"><!--綁定一個對應的Dao/Mapper接口--><!--之前是寫一個類實現Dao接口,如今綁定便可--><mapper namespace="com.mengyangchen.dao.StudentMapper"><!--sql語句嵌套思路:    1.查詢全部的學生信息    2.根據查詢出來的學生的tid,尋找對應的老師-->
    <resultMap id="studentTeacher" type="student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--複雜的屬性,咱們須要單獨處理 對象association 集合collection-->
        <association property="teacher" column="tid" javaType="Teacher">
            <result property="name" column="teacherName"/>
        </association>
    </resultMap><select id="selectStudentInfo" resultMap="studentTeacher">
  select s.id  id, s.name  name,t.name  teacherName from student s inner join teacher t on s.tid = t.id</select></mapper>

測試:

 @Test
    public void studentTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> list =  mapper.selectStudentInfo();
        for (Student student:list) {
            System.out.println(student);
        }
        sqlSession.close();
    }

在這裏插入圖片描述

04.一對多處理

一個老師對應多個學生
對於老師而言就是一對多。
實體類:

public class Teacher {
    private Integer id;
    private String name;
    //一個老師有多個學生
    private List<Student> student;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public List<Student> getStudent() {
        return student;
    }

    public void setStudent(List<Student> student) {
        this.student = student;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", student=" + student +
                '}';
    }}
public class Student {
    private Integer id;
    private String name;
    private Integer tid;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getTid() {
        return tid;
    }

    public void setTid(Integer tid) {
        this.tid = tid;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", tid=" + tid +
                '}';
    }}

接口:

public interface TeacherMapper {
    Teacher selectTeacherById(@Param("tid") int id);}

配置文件:

<?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"><!--綁定一個對應的Dao/Mapper接口--><!--之前是寫一個類實現Dao接口,如今綁定便可--><mapper namespace="com.mengyangchen.dao.TeacherMapper">

    <!--查詢語句-->
    <!--id相對於之前的書寫,表示重寫的方法名(之前在方法中執行鏈接數據庫等操做,如今不須要了,只須要執行sql-->
    <!--resultType返回結果-->

    <!--按照結果嵌套查詢--><select id="selectTeacherById" resultMap="teacherStudent">
     select s.id  id, s.name  name,t.name  teacherName from student s inner join teacher t on s.tid = t.id</select>

    <resultMap id="teacherStudent" type="teacher">
        <result property="name" column="teacherName"/>
        <collection property="student" ofType="Student">
            <result property="id" column="id"/>
            <result property="name" column="name"/>
        </collection>
    </resultMap></mapper>

在這裏插入圖片描述

05.動態sql

動態 SQL 是 MyBatis 的強大特性之一。若是你使用過 JDBC 或其它相似的框架,你應該能理解根據不一樣條件拼接 SQL 語句有多痛苦,例如拼接時要確保不能忘記添加必要的空格,還要注意去掉列表最後一個列名的逗號。利用動態 SQL,能夠完全擺脫這種痛苦。

若是你以前用過 JSTL 或任何基於類 XML 語言的文本處理器,你對動態 SQL 元素可能會感受似曾相識。在 MyBatis 以前的版本中,須要花時間瞭解大量的元素。藉助功能強大的基於 OGNL 的表達式,MyBatis 3 替換了以前的大部分元素,大大精簡了元素種類,如今要學習的元素種類比原來的一半還要少。

ifchoose (when, otherwise)trim (where, set)foreach

使用動態 SQL 最多見情景是根據條件包含 where 子句的一部分。好比:

<select id="findActiveBlogWithTitleLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’  <if test="title != null">
    AND title like #{title}
  </if></select>

動態sql之if

實現根據不一樣條件查詢數據!

實體類:

package com.mengyangchen.pojo;import java.util.Date;public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;//屬性名和字段名不一致
    private Integer views;

    public Blog() {
    }

    public String getId() {
        return id;
    }

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

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Integer getViews() {
        return views;
    }

    public void setViews(Integer views) {
        this.views = views;
    }

    @Override
    public String toString() {
        return "Blog{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", author='" + author + '\'' +
                ", createTime=" + createTime +
                ", views=" + views +
                '}';
    }}

接口:

package com.mengyangchen.dao;import com.mengyangchen.pojo.Blog;import java.util.List;import java.util.Map;public interface BlogMapper {
    /*插入數據*/
    int insertBlog(Blog blog);

    /*查詢博客*/
    List<Blog> queryBlogIf(Map map);}

配置文件:

<?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"><mapper namespace="com.mengyangchen.dao.BlogMapper">
   <insert id="insertBlog" parameterType="blog">
       insert into mybatis.blog (id,title,author,create_time,views) values (#{id},#{title},#{author},#{createTime},#{views});
   </insert>
    
    <select id="queryBlogIf" parameterType="map" resultType="blog">
        select * from mybatis.blog where 1=1
        <if test="title !=null">
            and title like "%"#{title}"%"
        </if>

        <if test="author != null">
            and author like "%"#{author}"%"
        </if>
    </select></mapper>

屬性名和字段名不一致,一個是下劃線,一個爲駝峯。

在這裏插入圖片描述

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd"><!--核心配置文件--><configuration><!--引入外部配置文件-->
    <properties resource="db.properties">
        <property name="username" value="root"/><!--一配置文件中爲準-->
        <property name="password" value="123456"/>
    </properties>

    <!--標準日誌實現-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--是否開啓自動駝峯命名規則映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!--別名-->
    <typeAliases>
        <package name="com.mengyangchen.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <!--事務管理-->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/><!--&amp是xml的轉義字符(即爲&)-->
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>

    </environments><mappers>
    <mapper class="com.mengyangchen.dao.BlogMapper"/></mappers></configuration>

動態sql之trim (where, set)

前面幾個例子已經方便地解決了一個臭名昭著的動態 SQL 問題。如今回到以前的 「if」 示例,此次咱們將 「state = ‘ACTIVE’」 設置成動態條件,看看會發生什麼。

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE  <if test="state != null">
    state = #{state}
  </if>
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if></select>

若是沒有匹配的條件會怎麼樣?最終這條 SQL 會變成這樣:

SELECT * FROM BLOG
WHERE

這會致使查詢失敗。若是匹配的只是第二個條件又會怎樣?這條 SQL 會是這樣:

SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’

這個查詢也會失敗。這個問題不能簡單地用條件元素來解決。這個問題是如此的難以解決,以致於解決過的人不會再想碰到這種問題。

MyBatis 有一個簡單且適合大多數場景的解決辦法。而在其餘場景中,能夠對其進行自定義以符合需求。而這,只須要一處簡單的改動:

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where></select>

where 元素只會在子元素返回任何內容的狀況下才插入 「WHERE」 子句。並且,若子句的開頭爲 「AND」 或 「OR」,where 元素也會將它們去除。
上個例子改完後:

<?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"><mapper namespace="com.mengyangchen.dao.BlogMapper">
   <insert id="insertBlog" parameterType="blog">
       insert into mybatis.blog (id,title,author,create_time,views) values (#{id},#{title},#{author},#{createTime},#{views});
   </insert>
    
    <select id="queryBlogIf" parameterType="map" resultType="blog">
        select * from mybatis.blog        <where>
            <if test="title !=null">
                title like "%"#{title}"%"
            </if>

            <if test="author != null">
                and author like "%"#{author}"%"
            </if>
        </where>

    </select>

   </mapper>

若是 where 元素與你指望的不太同樣,你也能夠經過自定義 trim 元素來定製 where 元素的功能。好比,和 where 元素等價的自定義 trim 元素爲:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...</trim>

prefixOverrides 屬性會忽略經過管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子會移除全部 prefixOverrides 屬性中指定的內容,而且插入 prefix 屬性中指定的內容。

用於動態更新語句的相似解決方案叫作 set。set 元素能夠用於動態包含須要更新的列,忽略其它不更新的列。好比:

解決了最後一個條件不須要,的問題。

<update id="updateAuthorIfNecessary">
  update Author    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}</update>

這個例子中,set 元素會動態地在行首插入 SET 關鍵字,並會刪掉額外的逗號(這些逗號是在使用條件語句給列賦值時引入的)。

來看看與 set 元素等價的自定義 trim 元素吧:

<trim prefix="SET" suffixOverrides=",">
  ...</trim>

動態sql之choose (when, otherwise)

有時候,咱們不想使用全部的條件,而只是想從多個條件中選擇一個使用。針對這種狀況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句。
仍是上面的例子,可是策略變爲:傳入了 「title」 就按 「title」 查找,傳入了 「author」 就按 「author」 查找的情形。若二者都沒有傳入,就返回標記爲 featured 的 BLOG

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’  <choose>
    <when test="title != null">
     AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose></select>

與if的區別只會執行一個條件。
練習:

 <select id="queryBlogChoose" parameterType="map" resultType="blog">
        select * from blog        <where>
            <choose>
                <when test="title != null">
                    title = #{title}
                </when>

                <when test="author != null">
                    and author = #{author}
                </when>
                <otherwise>
                    and views= #{views}
                </otherwise>
            </choose>
        </where>
    </select>
 @Test
    public void queryBlogChoose(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        Map map = new HashMap();
        map.put("title","Mybatis你好!");
        map.put("author","夢陽辰");
        List<Blog> list = mapper.queryBlogChoose(map);
        for (Blog blog:list) {
            System.out.println(blog);
        }
    }

在這裏插入圖片描述

動態sql之foreach

在這裏插入圖片描述

06.sql片斷

將一些通用的sql片斷提取出來。實現sql代碼的複用。
在這裏插入圖片描述

07.緩存

1.什麼是緩存?
存在內存中的臨時數據。
將用戶常常查詢的數據放在緩存((內存)中,用戶去查詢數據就不用從磁盤上(關係型數據庫數據文件)查詢,從緩存中查詢,從而提升查詢效率,解決了高併發系統的性能問題。

2.爲何使用緩存?
減小和數據庫的交互次數,減小系統開銷,提升系統效率。

3.什麼樣的數據能使用緩存?
常常查詢而且不常常改變的數據。
在這裏插入圖片描述
Mybatis緩存

MyBatis包含一個很是強大的查詢緩存特性,它能夠很是方便地定製和配置緩存。緩存能夠極大的提高查詢效率。

MyBatis系統中默認定義了兩級緩存:一級緩存和二級緩存

默認狀況下,只有一級緩存開啓。(SqlSession級別的緩存,也稱爲本地緩存)。

二級緩存須要手動開啓和配置,他是基於namespace級別的緩存。

爲了提升擴展性,MyBatis定義了緩存接口Cache。咱們能夠經過實現Cache接口來自定義二級緩存

一級緩存

MyBatis 內置了一個強大的事務性查詢緩存機制,它能夠很是方便地配置和定製。 爲了使它更增強大並且易於配置,咱們對 MyBatis 3 中的緩存實現進行了許多改進。
默認狀況下,只啓用了本地的會話緩存,它僅僅對一個會話中的數據進行緩存。

一級緩存也叫本地緩存:SqlSession

與數據庫同一次會話期間查詢到的數據會放在本地緩存中。
之後若是須要獲取相同的數據,直接從緩存中拿,沒必須再去查詢數據庫;

測試步驟:
1.開啓日誌!

2.測試在一個Sesion中查詢兩次相同記錄

3.查看日誌輸出

在這裏插入圖片描述

映射語句文件中的全部 select 語句的結果將會被緩存。
映射語句文件中的全部 insert、update 和 delete 語句會刷新緩存
緩存會使用最近最少使用算法(LRU, Least Recently Used)算法來清除不須要的緩存。
緩存不會定時進行刷新(也就是說,沒有刷新間隔)。
緩存會保存列表或對象(不管查詢方法返回哪一種)的 1024 個引用。
緩存會被視爲讀/寫緩存,這意味着獲取到的對象並非共享的,能夠安全地被調用者修改,而不干擾其餘調用者或線程所作的潛在修改。

緩存失效的狀況:
1.查詢不一樣的內容

2.增刪改操做,可能會改變原來的數據,因此會刷新緩存。

3.查詢不一樣的Mapper.xml

4.手動清除緩存。

sqlSession.clearCache();//手動清理緩存

一級緩存存在於sqlsession得到到關閉,默認開啓(有效期在得到鏈接到關閉鏈接)。

二級緩存

二級緩存也叫全局緩存,一級緩存做用域過低了,因此誕生了二級緩存·

基於namespace級別的緩存,一個名稱空間,對應一個二級緩存;

工做機制
一個會話查詢一條數據,這個數據就會被放在當前會話的一級緩存中;

若是當前會話關閉了,這個會話對應的一級緩存就沒了;可是咱們想要的是,會話關閉了,一級緩存中的數據被保存到二級緩存中;

新的會話查詢信息,就能夠從二級緩存中獲取內容;

不一樣的mapper查出的數據會放在本身對應的緩存(map)中;

默認狀況下,只啓用了本地的會話緩存(一級緩存),它僅僅對一個會話中的數據進行緩存。 要啓用全局的二級緩存,只須要在你的 SQL 映射文件中添加一行:

<cache/>

緩存只做用於 cache 標籤所在的映射文件中的語句。若是你混合使用 Java API 和 XML 映射文件,在共用接口中的語句將不會被默認緩存。你須要使用 @CacheNamespaceRef 註解指定緩存做用域。

這些屬性能夠經過 cache 元素的屬性來修改。好比:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

這個更高級的配置建立了一個 FIFO 緩存,每隔 60 秒刷新,最多能夠存儲結果對象或列表的 512 個引用,並且返回的對象被認爲是隻讀的,所以對它們進行修改可能會在不一樣線程中的調用者產生衝突。

可用的清除策略有:

LRU – 最近最少使用:移除最長時間不被使用的對象。
FIFO – 先進先出:按對象進入緩存的順序來移除它們。
SOFT – 軟引用:基於垃圾回收器狀態和軟引用規則移除對象。
WEAK – 弱引用:更積極地基於垃圾收集器狀態和弱引用規則移除對象。
默認的清除策略是 LRU。

步驟:
1.開啓全局緩存(默認開啓)。
在這裏插入圖片描述
2.在要使用二級緩存的Mapper中開啓
在這裏插入圖片描述
3.問題:咱們須要將實體類序列化!不然會報錯。

implements Serializable

只要開啓了二級緩存,在同一個Mapper下就有效。

全部的數據都會先放在一級緩存中。

只有當會話提交,或者關閉的時候,纔會提交到二級緩存中!

緩存的原理

在這裏插入圖片描述

自定義緩存

EhCache 是一個純Java的進程內緩存框架,具備快速、精幹等特色,是Hibernate中默認的CacheProvider。
1.導包

第三方緩存<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --><dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.1.0</version></dependency>

除了上述自定義緩存的方式,你也能夠經過實現你本身的緩存,或爲其餘第三方緩存方案建立適配器,來徹底覆蓋緩存行爲。

<cache type="com.domain.something.MyCustomCache"/>

這個示例展現瞭如何使用一個自定義的緩存實現。type 屬性指定的類必須實現 org.apache.ibatis.cache.Cache 接口,且提供一個接受 String 參數做爲 id 的構造器。 這個接口是 MyBatis 框架中許多複雜的接口之一,可是行爲卻很是簡單。

public interface Cache {
  String getId();
  int getSize();
  void putObject(Object key, Object value);
  Object getObject(Object key);
  boolean hasKey(Object key);
  Object removeObject(Object key);
  void clear();}

放假回家已經好幾天啦,感受要學習的東西還不少。加油,下一篇spring見!

在這裏插入圖片描述

相關文章
相關標籤/搜索