MyBatis學習筆記(炒雞詳細)

MyBatis學習

博主此篇學習筆記是跟隨嗶哩嗶哩UP主:狂神說Java,視頻講解時整理
UP主鏈接:https://space.bilibili.com/95256449

簡介:

MyBatis是一款優秀的持久層框架
它支持定製化SQL、存儲過程以及高級映射。
MyBatis避免了幾乎所有的JDBC代碼和手動設置參數以及獲取結果集。
MyBatis可以使用簡單的XML或註解來配置和映射原生類型、接口和Java的POJO爲數據庫中的記錄。

特點:

  • 簡單易學、靈活、sql和代碼的分離,提高了可維護性。
  • 提供映射標籤,支持對象與數據庫的orm字段關係映射;
  • 提供對象關係映射標籤,支持對象關係組建維護
  • 提供xml標籤,支持編寫動態sql。

使用:

1、搭建環境(如:pom.xml中加入mysql驅動、mybatis、junit一些依賴)

<!--    導入依賴-->
    <dependencies>
        <!--        mysql驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>
        <!--        mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <!--        junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
    </dependencies>

2、創建一個模塊(加入mybatis核心配置文件:mybatis-config.xml(resources文件中創建),mybatis工具類)

mybatis-config.xml

<?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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!--    每一個Mapper.XML都需要在Mybatis核心配置文件中註冊-->
    <mappers>
        <mapper resource="Mapper/UserMapper.xml"/>
    </mappers>
</configuration>

MybatisUtils.java

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //使用Mybatis第一步:獲取sqlSessionFactory對象;
            String resource = "mybatis-config.xml";
            InputStream inputStream = null;
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //即然有了SqlSessionFactory,顧名思義,我們就可以從中獲得SqlSession的實例。
    //SqlSession完全包含了面向數據庫執行SQL命令所需的所有方法。
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

3、編寫代碼(創建pojo包中實體類,mapper接口(相當於dao接口),mapper.xml文件(寫sql語句,相當於dao接口的實現類;在resources文件中創建))
在這裏插入圖片描述
User.java

public class User {
    private int id;
    private String name;
    private String pwd;

    public User() {
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    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 String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

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

UserMapper.java

package com.kx.dao;

import com.kx.pojo.User;

import java.util.List;

public interface UserMapper {
    //查詢所有
    List<User> getUserList();
    //根據id查詢
    User getUser(int id);
    //增加一條數據
    int insertUser(User user);
    //修改數據
    int updateUser(User user);
    //刪除數據
    int deleteUser(int id);
}

UserMapper.xml

<?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.kx.dao.UserMapper">
    <!--    查詢所有-->
    <select id="getUserList" resultType="com.kx.pojo.User">
        select * from mybatis.user
    </select>
    <!--    根據id查詢-->
    <select id="getUser" resultType="com.kx.pojo.User">
        select * from user where id = #{id}
    </select>
    <!--    插入數據-->
    <insert id="insertUser" parameterType="com.kx.pojo.User">
        insert into user (id,name,pwd) value (#{id},#{name},#{pwd})
    </insert>
    <!--    修改數據-->
    <update id="updateUser" parameterType="com.kx.pojo.User">
        update user set name=#{name},pwd=#{pwd} where id = #{id}
    </update>
<!--    刪除數據-->
    <delete id="deleteUser" parameterType="int">
        delete from user where id = #{id}
    </delete>
</mapper>

4、測試(創建測試類進行創建)

UserDaoTest.java

import com.kx.pojo.User;
import com.kx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserDaoTest {

    @Test
    public void test(){

        //第一步:獲得SqlSession對象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserList();

        for (User user : userList) {
            System.out.println(user);
        }
        //關閉SqlSession
        sqlSession.close();
    }

    @Test
    public void getUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.getUser(1);
        System.out.println(user);
        sqlSession.close();
    }

    @Test
    public void insertUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int res = mapper.insertUser(new User(3, "哈哈哈", "46567"));
        if (res>0){
            System.out.println("插入成功");
        }
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int res = mapper.updateUser(new User(3, "嘿嘿嘿", "75644"));
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int res = mapper.deleteUser(3);
        sqlSession.commit();
        sqlSession.close();
    }
}

增刪改查

namespace
namespace的包名要和mapper接口的包名一致
select、insert、update、Delete
選擇,查詢語句;
id:就是對應的namespace中的方法名;
resultType:Sql語句執行的返回值
parameterType:參數類型

步驟

1、編寫接口
2、編寫對應的mapper中的sql語句
3、測試
注意:增刪改需要提交事務

配置解析

1、核心配置文件

mybatis-config.xml

MyBatis的配置文件包含了會深深影響MyBatis行爲的設置和屬性信息

configuration(配置)
properties(屬性)
setting(設置)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境配置)
environment(環境變量)
transactionManager(事務管理器)
dataSource(數據源)
databaseIdProvider(數據庫廠商標識)
mappers(映射器)

2、環境配置(environments)

MyBatis可以配置成適應多種環境
注意:儘管可以配置多個環境,但每個SqlSessionFactory實例只能選擇一種環境。
Mybatis默認的事務管理器就是JDBC,連接池:POOLED

3、屬性(properties)

可以通過properties屬性來實現引用配置文件
這些屬性都是可外部配置且可動態替代的,既可以在典型的java屬性文件中配置,也可通過properties元素的子元素來傳遞。

編寫配置文件

db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8
username=root
password=123456

在覈心配置文件中映入

<!--    引入外部配置文件-->
<properties resource="db.properties">
    <property name="username" value"root"/>
    <property name="pwd" value="123456"/>
</properties>
  • 可以直接引入外部文件
  • 可以在其中增加一些屬性配置
  • 如果兩個文件有統一字段,優先使用外部配置文件

4、類型別名(typeAliases)

  • 類型別名是爲了Java類型設置一個短的名字。
  • 存在的意義僅在於用來減少類完全限定名的冗餘。
<!--    可以給實體類起別名-->
<typeAliases>
    <typeAlias type="com.kx.pojo.User" alias="User"/>
</typeAliases>

也可以指定一個包名,MyBatis會在包名下面搜索需要的Java Bean,比如:掃描實體類的包,它的默認別名就爲這個類的類名,首字母小寫

<typeAliases>
    <package name="com.kx.pojo"/>
</typeAliases>

在實體類比較少使,使用第一種方式

若實體類十分多,鍵入使用第二種

第一種可以DIY別名,第二種則需要在實體上增加註解纔可DIY別名

@Alias("user")
public class User{}

5、映射器(mappers)

MapperRegistry:註冊綁定我們的Mapper文件;

方式一:

<!--    每一個Mapper.XML都需要在Mybatis核心配置文件中註冊-->
<mappers>
    <mapper resource="Mapper/UserMapper.xml"/>
</mappers>

方式二:使用class文件綁定註冊

<mappers>
    <mapper class="com.kx.daoUserMapper"/>
</mappers>

方式三:使用掃描包進行注入綁定

<mappers>
    <package name="com.kx.dao"/>
</mappers>

注意:

方式二和方式三中

  • 接口和它的Mapper配置文件必須同名
  • 接口和它的Mapper配置文件必須在同一個包下

6、生命週期和作用域

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-l6eukVGs-1586162967745)(C:\Users\K.X\AppData\Roaming\Typora\typora-user-images\image-20200331155439999.png)]

生命週期,和作用域,是至關重要的,因爲錯誤的使用會導致非常嚴重的併發問題

SqlSessionFactoryBuilder:

  • 一旦創建了SqlSessionFactory,就不再需要它了
  • 局部變量

SqlSessionFactory:

  • 可以想象爲:數據庫連接池
  • SqlSessionFactory一旦被創建就應該在應用的運行期限一直存在,沒有任何理由丟棄它或重新創建另一實例。
  • 因此SqlSessionFactory的最佳作用域是應用作用域。
  • 最簡單的就是使用單例模式或者靜態單例模式。

SqlSession

  • 連接到連接池的一個請求!
  • SqlSession的實例不是線程安全的,因此是不能被共享的,所以它的最佳的作用域是請求或方法作用域。
  • 用完之後需要關閉,否則資源被佔用

解決屬性名和字段名不一致的問題

實體類中的屬性名和數據庫的屬性名不一致:

解決方法

方式一:起別名

<select id="getUsers" resultType="user">
     select id,name,pwd as password from user where id=#{id}
</select>

方式二

resultMap

<!--結果集映射-->
<resultMap id="UserMap" type="user">
	<!--column數據庫中的字段,property實體類中的屬性-->
 <result column="id" property="id"/>
 <result column="name" property="name"/>
 <result column="pwd" property="password"/>
</resultMap>

<select id="getUserById" resultMap="UserMap">
 select * from user where id = #{id}
</select>
  • ResultMap的設計思想是,對於簡單的語句根本不需要配置顯式的結果映射,而對於複雜一點的語句只需要描述它們的關係就行了。對於沒有變化的字段可以不用映射,只對字段不同的映射就好了
<resultMap id="UserMap" type="user">
	<!--column數據庫中的字段,property實體類中的屬性-->
   <result column="pwd" property="password"/>
</resultMap>

日誌

日誌工廠

如果一個數據庫操作,出現了異常,日誌就是最好的助手!

logImpl 指定MyBatis所用日誌的具體實現,未指定時將自動查找

  • SLF4J
  • LOG4J
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING
  • NO_LOGGING

在Mybatis中具體使用哪一個日誌實現,在設置中設定

STDOUT_LOGGING標準日誌輸出

在mybatis核心配置文件中,配置日誌

<!--標準工廠日誌實現-->
<settings>
	<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

Log4j

  • Log4j是Apache的一個開源項目,通過使用Log4j,我們可以控制日誌信息輸送的目的地是控制檯、文件、GUI組件
  • 也可以控制每一條日誌的輸出格式;
  • 通過定義每一條日誌信息的級別,我們能夠更加細緻地控制日誌的生成過程
  • 通過一個配置文件來靈活地進行配置,而不需要修改應用的代碼

1、先導入log4j的包

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

2、log4j.properties

#將等級爲DEBUG的日誌信息輸出到console和file這兩個目的地,console和file的定義在下面的代碼
log4j.rootLogger=DEBUG,console,file

#控制檯輸出的相關設置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件輸出的相關設置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kx.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日誌輸出級別
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

3、配置log4j爲日誌的實現

<settings>
	<setting name="logImpl" value="LOG4J"/>
</settings>

簡單使用

​ 1.在要使用Log4j的類中,導入包import org.apache.log4j.Logger;

​ 2.日誌對象,參數爲當前類的class

static Logger logger = Logger.getLogger(UserDaoTest.class);

​ 3.日誌級別

logger.info("info:進入了testLog4j");
logger.debug("debug:進入了testLog4j");
logger.error("error:進入了testLog4j");

分頁

完成返回前幾條或者中間某幾行數據,減少數據的處理量

使用Limit分頁

語法:
select * from user limit startIndex,pageSize;
select * from user limit n; #[0,n]

接口

//分頁查詢
List<User> getUserByLimit(Map<String,Integer> map);

Mapper.xml

<!--    分頁查詢-->
<select id="getUserByLimit" parameterType="map" resultType="User">
    select * from user limit #{startIndex},#{pageSize}
</select>

測試

@Test
public void getUserByLimit(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map<String,Integer> map = new HashMap<String, Integer>();
    map.put("startIndex",0);
    map.put("pageSize",1);
    List<User> userList = mapper.getUserByLimit(map);
    for (User user : userList) {
        System.out.println(user);
    }
    //關閉SqlSession
    sqlSession.close();
}

使用註解開發

面向接口編程

根本原因:解耦,可拓展,提高複用,分層開發中,上層不用管具體的實現,大家都遵守共同的標準,使得開發變得容易,規範性更好

-在一個面向對象的系統中,系統的各種功能是由許許多多的不同對象協作完成的。在這種情況下,各個對象內部是如何實現自己的,對系統設計人員來說就不那麼重要了;

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

關於接口的理解

-接口從更深層次的理解,應是定義(規範,約束)與實現(名實分離的原則)的分離。

-接口的本身反映了系統設計人員對系統的抽象理解。

-接口應有兩類:

​ -一類是對一個個體的抽象,它可對應爲一個抽象體(abstract class);

​ -一類是對一個個體某一方面的抽象,即形成一個抽象面(interface);

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

三個面向區別

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

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

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

使用註解開發

  1. 註解在接口上實現

    @Select("select * from user")
    List<User> getUserList();
    
  2. 需要在覈心配置文件中綁定接口

    <mappers>
        <mapper class="com.kx.dao.UserMapper"/>
    </mappers>
    

CRUD

我們可以在工具類創建時實現自動提交事務

public static SqlSession getSqlSession() {
    return sqlSessionFactory.openSession(true);
}

編寫接口,增加註解

public interface UserMapper {
 
    @Select("select * from user")
    List<User> getUserList();

    //方法存在多個參數,所有參數前必須加上 @Param("id")註解
    @Select("select * from user where id = #{id}")
    User getByID(@Param("id") int id);

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

    @Update("update from user set name=#{name},pwd=#{pwd} where id=#{id}")
    int updateUser(User user);

    @Delete("delete from user where id = #{id}")
    int deleteUser(@Param("id") int id);
}

注意:必須要將接口註冊綁定到核心配置文件中

關於@Param() 註解

  • 基本類型的參數或者String類型,需要加上
  • 引用類型不需要加
  • 在SQL中引用的是@Param() 中設定的屬性名

Lombok

  1. 在IDEA中安裝Lombok插件

  2. 在項目中導入Lombok的jar包

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
    
  3. 在實體類中加入註解即可使用

    @Data:無參構造,get,set,tostring,hashcode,equals
    @AllArgsConstructor:有參構造
    @NoArgsConstructor:無參構造
    

聯表查詢

多對一處理

多個學生對應一名老師

實體類

@Data
public class Student {
    private int id;
    private String name;
    private Teacher teacher;
}
@Data
public class Teacher {
    private int id;
    private String name;
}

子查詢,按照查詢嵌套處理

<!--    思路:
           1、查詢所有學生
           2、根據學生的tid,尋找對應的老師
-->
<select id="getStudent" resultMap="StudentTeacher">
    select * from student
</select>
<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="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="teacher">
    select * from teacher where id = #{id}
</select>

連接查詢,按照結果嵌套處理

<!--    按照結果嵌套處理-->
<select id="getStudent" resultMap="StudentTeacher">
    select s.id sid, s.name sname, t.name tname
    from student s,teacher t
    where s.tid = t.id
</select>
<resultMap id="StudentTeacher" type="Student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="teacher">
        <result property="name" column="tname"/>
    </association>
</resultMap>

一對多處理

一個老師擁有多名學生

實體類:

@Data
public class Teacher {
    private int id;
    private String name;
    //一個老師擁有多名學生
    private List<Student> students;
}
@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}

子查詢,按照查詢嵌套處理

<select id="getTeacher" resultMap="TeacherStudent">
    select * from teacher where id = #{tid} 
</select>
<resultMap id="TeacherStudent" type="teacher">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <collection property="students" column="id" javaType="ArrayList" ofType="student" select="getStudentByTeacherID"/>
</resultMap>
<select id="getStudentByTeacherID" resultType="student">
    select * from student where tid = #{tid}
</select>

連接查詢,按照結果嵌套處理

<select id="getTeacher" resultMap="TeacherStudent">
    select s.id sid, s.name sname, t.name tname, t.id tid
    from student s, teacher t
    where s.tid = t.id and t.id=#{tid}
</select>
<resultMap id="TeacherStudent" type="teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <!--        javaType="" 指定屬性的類型
                    集合中的泛型信息,我們使用ofType獲取
        -->
    <collection property="students" ofType="student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

小結:

  1. 關聯 - association 【多對一】
  2. 集合 - collection 【一對多】
  3. javaType & ofType
    1. JavaType 用來指定實體類中屬性的類型
      2. ofType 用來指定映射到List或者集合中的pojo類型,泛型中的約束類型

注意點

  • 保證SQL的可讀性,儘量保證通俗易懂
  • 注意一對多和多對一中,屬性名和字段的問題

動態SQL

什麼是動態SQL:動態SQL就是指根據不同的條件生成不同的SQL語句

可以根據不同條件進行SQL拼接。

if

choose ( when, otherwise)

trim (where, set)

foreach

where&if

<select id="queryBlog" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </where>
</select>

choose ( when, otherwise)

相當於Java中的switch語句

<select id="chooseBlog" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <choose>
            <when test="title != null">
                and title = #{title}
            </when>
            <when test="author">
                and author = #{author}
            </when>
            <otherwise>
                views = #{views}
            </otherwise>
        </choose>
    </where>
</select>

trim(set,where)

<update id="updateBlog" parameterType="map">
    update blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="auther != null">
            auther = #{auther}
        </if>
    </set>
    where id = #{id}
</update>

trim標籤可自定義格式,實現where與set標籤功能

foreach

<!-- select * from blog where 1=1 and (id=1 or id=2 or id=3)   -->
<select id="foreachBlog" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <foreach collection="ids" item="id" open="and (" close=")" separator="or">
            id = #{id}
        </foreach>
    </where>
</select>

SQL片段

有的時候,我們可能會將一些功能的部分抽取出來,方便複用!

  1. 使用SQL標籤抽取公共的部分

    <sql id="if-title-author">
    	<if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </sql>
    
  2. 在需要使用的地方使用include標籤引用即可

    <select id="queryBlog" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <include refid="if-title-author"></include>
        </where>
    </select>
    

注意

  • 最好基於單表來定義SQL片段
  • 不要存在where標籤

緩存

  1. 什麼是緩存
    • 存在內存中的臨時數據。
    • 將用戶經常查詢的數據放在緩存(內存)中,用戶去查詢數據就不用從磁盤上(關係型數據庫數據文件)查詢,從緩存中查詢,從而提高查詢效率,解決了高併發系統的性能問題。
  2. 爲什麼使用緩存
    • 減少和數據庫的交互次數,減少系統開銷,提高系統效率。
  3. 什麼樣的的數據能使用緩存?
    • 經常查詢並且不經常改變的數據。

Mybatis緩存

  • MyBatis包含一個非常強大的查詢緩存特性,它可以非常方便地定製和配置緩存。緩存可以極大地提升查詢效率。
  • MyBatis系統中默認定義了兩級緩存:一級緩存二級緩存
    • 默認情況下,只有一級緩存開啓。(SqlSession級別的緩存,也稱爲本地緩存)
    • 二級緩存需要手動開啓和配置,是基於namespace級別的緩存。
    • 爲了提高擴展性,MyBatis定義了緩存接口Cache。可以通過實現Cache接口來自定義二級緩存

一級緩存

  • 一級緩存也叫本地緩存:SqlSession
    • 與數據庫同一次會話期間查詢到的數據會放到本地緩存中。
    • 以後如果需要獲取相同的數據,可以直接從緩存中拿,不用再查詢數據庫;

緩存失效的情況:

  1. 查詢不同的東西

  2. 增刪改操作,可能會改變原來的數據,所以必定會刷新緩存

  3. 查詢不同的Mapper.xml

  4. 手動清理緩存。

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

小結:

一級緩存默認是開啓的,只在一次SqlSession中有效,也就是拿到連接到關閉連接這個區間段。

一級緩存相當於是一個map.

二級緩存

  • 二級緩存也叫全局緩存,一級緩存作用域低,所以產生了二級緩存
  • 基於namespace級別的緩存,一個名稱空間,對應一個二級緩存;
  • 工作機制
    • 一個會話查詢一條數據,這個數據就會被放在當前會話的一級緩存中;
    • 如果當前會話關閉了,這個會話對應的一級緩存就沒了;但是我們需要的是,會話關閉,一級緩存中的數據被保存到二級緩存中;
    • 新的會話查詢信息,就可以從二級緩存中獲取內容;
    • 不同的mapper查出的數據會放在自己對應的緩存(map)中;

步驟

  1. 開啓全局緩存

    <!--顯示的開啓全局緩存(默認也是開啓)-->
    <setting name="cacheEnabled" value="true"/>
    
  2. 在要使用二級緩存的Mapper中開啓

    <!--在當前Mapper.xml中使用二級緩存-->
    <cache/>
    

    也可以自定義參數

    <!--在當前Mapper.xml中使用二級緩存-->
    <cache
      eviction="FIFO"
      flushInterval="60000"
      size="512"
      readOnly="true"/>
    

小結:

  • 只要開啓了二級緩存,在同一個Mapper下就有效
  • 所有的數據都會先放在一級緩存中;
  • 只有當會話提交,或者關閉的時候,纔會提交到二級緩存中

緩存順序

查詢順序

  1. 先看二級緩存中有沒有
  2. 再看一級緩存中有沒有
  3. 查詢數據庫
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章