MyBatis學習筆記整理詳細

MyBatis筆記

寫在前面:歡迎來到「發奮的小張」的博客。我是小張,一名普通的在校大學生。在學習之餘,用博客來記錄我學習過程中的點點滴滴,也希望我的博客能夠更給同樣熱愛學習熱愛技術的你們帶來收穫!希望大家多多關照,我們一起成長一起進步。也希望大家多多支持我鴨,喜歡我就給我一個關注吧!


官方文檔:https://mybatis.org/mybatis-3/zh/index.html

1.配置


  1. mysql數據庫
  2. Maven
  3. mybatis3.6.1

2.目錄結構

在這裏插入圖片描述

3.MyBatisUtils.java配置

package com.zhang.utils;

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;


/**
 * 工具類
 */
//sqlSessionFactory-->sqlSession
public class MyBatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //使用mubatisd第一步:獲取sqlSessionFactory對象

//            String resource = "org/mybatis/example/mybatis-config.xml";
            String resource = "./mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //第二步:獲取對象
    //既然有了 SqlSessionFactory,顧名思義,
    //我們可以從中獲得 SqlSession 的實例
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }


}

4.pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rui</groupId>
    <artifactId>MyBatistest</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <!--父工程-->
    <dependencies>
        <!--mysql驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</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.12</version>
        </dependency>
    </dependencies>


<!--配置資源路徑-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>

            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>


</project>

5.Mapper.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">
//namespace是搭建Dao操作與Mapper接口的連接
<mapper namespace="com.zhang.dao.UserDao">
//id是調用Dao裏的函數名
    <select id="getUserList" 
    //resultType是用來保存查詢結果封裝到User類中
    resultType="com.zhang.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

注意:運行時建議刪除Mapper.xml中文註釋,防止中文產生的報錯情況

6.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.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    //每次增加mapper.xml記得註冊到這裏
    <mappers>
        <mapper resource="com/zhang/dao/UserMapper.xml"/>
    </mappers>
</configuration>

注意:config-xml的中文註釋建議運行時刪除,防止運行出錯,每次新增Mapper.xml記得註冊到這裏

7.CRUD操作

1.namespace

namespace中的包名要和Dao/Mapper接口的包名一致

2.select

選擇,查詢語句

  • id:就是對應的namespace中的方法名
  • resultType:sql語句執行的返回值
  • parameterType:參數類型
  1. 編寫接口

    import com.zhang.pojo.User;
    
    import java.util.List;
    
    public interface UserMapper {
        /**
         * 查詢全部用戶
         * @return
         */
        public List<User> getUserList();
    
        /**
         * 根據id查詢用戶
         * @param id
         * @return
         */
        public User getUserById(int id);
    
        /**
         * 添加一個用戶
         * @param user
         * @return
         */
        public int insert(User user);
    
        /**
         * 修改用戶
         * @param user
         * @return
         */
        public int updateUser(User user);
    
        /**
         * 刪除
         * @param id
         * @return
         */
        public int deleteUser(int id);
    }
    
  2. 編寫Mapper.xml對應的sql語句

    <?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.zhang.dao.UserMapper">
        <select id="getUserList" resultType="com.zhang.pojo.User">
            select * from mybatis.user
        </select>
    
        <select id="getUserById" parameterType="int" resultType="com.zhang.pojo.User">
            select * from mybatis.user where id=#{id}
        </select>
    
        <insert id="insert" parameterType="com.zhang.pojo.User">
            insert into mybatis.user (id,name ,pwd) values (#{id},#{name},#{pwd})
        </insert>
    
        <update id="updateUser" parameterType="com.zhang.pojo.User">
            update mybatis.user set name = #{name},pwd=#{pwd} where id=#{id};
        </update>
        
        <delete id="deleteUser" parameterType="int">
            delete from mybatis.user where id=#{id}
        </delete>
    </mapper>
    
  3. 測試

    package com.zhang.dao;
    
    import com.zhang.pojo.User;
    import com.zhang.utils.MyBatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.junit.Test;
    
    import java.util.List;
    
    public class UserDaoTest {
        @Test
        public void test(){
            //獲得sqlsession對象
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
            //執行sql
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<User> userList = mapper.getUserList();
    
            //打印
            for (User user:userList) {
                System.out.println(user);
            }
    
            //關閉sqlsessiopn
            sqlSession.close();
        }
        @Test
        public void getUserById(){
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            User use = mapper.getUserById(1);
    
            System.out.println(use);
    
            sqlSession.close();
        }
        @Test
        public void addUser(){
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            int t = mapper.insert(new User(6, "李老六", "111"));
    
            if (t>0){
                System.out.println("插入成功!");
                //提交事務
                sqlSession.commit();
            }
    
            sqlSession.close();
        }
        @Test
        public void updateUser(){
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            int i = mapper.updateUser(new User(2, "大傻子", "222"));
    
            if (i>0){
                System.out.println("修改成功!");
                sqlSession.commit();
            }
            sqlSession.close();
        }
        @Test
        public void deleteUser(){
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            int i = mapper.deleteUser(2);
    
            if (i>0){
                System.out.println("刪除成功!");
                sqlSession.commit();
            }
            sqlSession.close();
        }
    }
    
    

3.增刪改均需要提交事務,否則數據無法寫入數據庫

//提交事務
sqlSession.commit();

4.優化CRUD操作

1.萬能Map

  • 假設我們的實體類,或者數據庫中的表,字段或者參數過多,我們應當考慮使用Map!

  •    /**
         * 添加多個
         * @param map
         * @return
         */
        public int addUser2(Map<String,Object> map);
    
    
    
  •     <insert id="addUser2" parameterType="map">
            insert into mybatis.user (id,name ,pwd) values (#{userid},#{username},#{userpwd})
        </insert>
    
  •        map.put("userid","8");
            map.put("username","王老六");
            map.put("userpwd","888888");
         
            mapper.addUser2(map);
    
    
    **這樣可以達到參數靈活使用**
    
    Map傳遞參數,直接在sql中取出key即可!【parameterType="map"】
    
    對象傳遞參數,直接在sql中取出對象的屬性即可!【parameterType="com.zhang.pojo.User"】
    
    只有一個基本類型參數情況下,可以直接在sql中取到!【parameterType="int"】
    
    **多個參數用Map或者註解**
    

2.模糊查詢

模糊查詢怎麼寫?

1,java代碼執行時,傳遞通配符% %

List<User> list = mapper.getUserLike("李");

2.在sql拼接中使用通配符!

select * from mybatis.user where name like "%"#{value}"%"

8.配置解析

1.核心配置文件

網頁鏈接:https://mybatis.org/mybatis-3/zh/configuration.html

  • mybatis-config.xml
  • MyBatis 的配置文件包含了會深深影響 MyBatis 行爲的設置和屬性信息。
configuration(配置)
properties(屬性)
settings(設置)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境配置)
environment(環境變量)
transactionManager(事務管理器)
dataSource(數據源)
databaseIdProvider(數據庫廠商標識)
mappers(映射器)

2.環境配置(environments)

MyBatis 可以配置成適應多種環境

不過要記住:儘管可以配置多個環境,但每個 SqlSessionFactory 實例只能選擇一種環境。

注意一些關鍵點:

  • 默認使用的環境 ID(比如:default=“development”)。
  • 每個 environment 元素定義的環境 ID(比如:id=“development”)。
  • 事務管理器的配置(比如:type=“JDBC”)。
  • 數據源的配置(比如:type=“POOLED”)。

Mybatis默認的事務管理器是jdbc,連接池:POOLED

學會使用配置多套環境

3.屬性(properties)(掌握)

我們可以通過properties屬性來實現引用配置

這些屬性可以在外部進行配置,並可以進行動態替換。你既可以在典型的 Java 屬性文件中配置這些屬性,也可以在 properties 元素的子元素中設置。 【db.properties】

編寫配置文件:

db.properties

driver = com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username=root
password=root

在覈心配置文件中引入:

<properties resource="org/mybatis/example/config.properties">
  <property name="username" value="dev_user"/>
  <property name="password" value="F2Fa3!33TYyg"/>
</properties>

可以直接引入外部文件

可以在其中增加屬性配置

如果外部和內部字段相同,優先使用外部屬性

4.類型別名(typeAliases)(掌握)

  • 類型別名可爲 Java 類型設置一個縮寫名字。
  • 它僅用於 XML 配置,意在降低冗餘的全限定類名書寫 .
 <typeAlias type="com.zhang.pojo.User" alias="User"/>

也可以指定一個包名,MyBatis 會在包名下面搜索需要的 Java Bean .

掃描實體類的包,它默認別名就是這個實體類的類名,首字母小寫。

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

在實體類少的時候,使用第一種方式。

在實體類多的時候,建議使用第二種。

還可以在實體類上增加註解

@Alias("user")
public class User {

下面是一些爲常見的 Java 類型內建的類型別名。它們都是不區分大小寫的,注意,爲了應對原始類型的命名重複,採取了特殊的命名風格。

別名 映射的類型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
object Object
map Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator

5.設置(settings)

這是 MyBatis 中極爲重要的調整設置,它們會改變 MyBatis 的運行時行爲。 下表描述了設置中各項設置的含義、默認值等。

設置名 描述 有效值 默認值
cacheEnabled 全局性地開啓或關閉所有映射器配置文件中已配置的任何緩存。 true | false true
lazyLoadingEnabled 延遲加載的全局開關。當開啓時,所有關聯對象都會延遲加載。 特定關聯關係中可通過設置 fetchType 屬性來覆蓋該項的開關狀態。 true | false false
aggressiveLazyLoading 開啓時,任一方法的調用都會加載該對象的所有延遲加載屬性。 否則,每個延遲加載屬性會按需加載(參考 lazyLoadTriggerMethods)。 true | false false (在 3.4.1 及之前的版本中默認爲 true)
multipleResultSetsEnabled 是否允許單個語句返回多結果集(需要數據庫驅動支持)。 true | false true
useColumnLabel 使用列標籤代替列名。實際表現依賴於數據庫驅動,具體可參考數據庫驅動的相關文檔,或通過對比測試來觀察。 true | false true
useGeneratedKeys 允許 JDBC 支持自動生成主鍵,需要數據庫驅動支持。如果設置爲 true,將強制使用自動生成主鍵。儘管一些數據庫驅動不支持此特性,但仍可正常工作(如 Derby)。 true | false False
autoMappingBehavior 指定 MyBatis 應如何自動映射列到字段或屬性。 NONE 表示關閉自動映射;PARTIAL 只會自動映射沒有定義嵌套結果映射的字段。 FULL 會自動映射任何複雜的結果集(無論是否嵌套)。 NONE, PARTIAL, FULL PARTIAL
autoMappingUnknownColumnBehavior 指定發現自動映射目標未知列(或未知屬性類型)的行爲。NONE: 不做任何反應WARNING: 輸出警告日誌('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日誌等級必須設置爲 WARNFAILING: 映射失敗 (拋出 SqlSessionException) NONE, WARNING, FAILING NONE
defaultExecutorType 配置默認的執行器。SIMPLE 就是普通的執行器;REUSE 執行器會重用預處理語句(PreparedStatement); BATCH 執行器不僅重用語句還會執行批量更新。 SIMPLE REUSE BATCH SIMPLE
defaultStatementTimeout 設置超時時間,它決定數據庫驅動等待數據庫響應的秒數。 任意正整數 未設置 (null)
defaultFetchSize 爲驅動的結果集獲取數量(fetchSize)設置一個建議值。此參數只可以在查詢設置中被覆蓋。 任意正整數 未設置 (null)
defaultResultSetType 指定語句默認的滾動策略。(新增於 3.5.2) FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同於未設置) 未設置 (null)
safeRowBoundsEnabled 是否允許在嵌套語句中使用分頁(RowBounds)。如果允許使用則設置爲 false。 true | false False
safeResultHandlerEnabled 是否允許在嵌套語句中使用結果處理器(ResultHandler)。如果允許使用則設置爲 false。 true | false True
mapUnderscoreToCamelCase 是否開啓駝峯命名自動映射,即從經典數據庫列名 A_COLUMN 映射到經典 Java 屬性名 aColumn。 true | false False
localCacheScope MyBatis 利用本地緩存機制(Local Cache)防止循環引用和加速重複的嵌套查詢。 默認值爲 SESSION,會緩存一個會話中執行的所有查詢。 若設置值爲 STATEMENT,本地緩存將僅用於執行語句,對相同 SqlSession 的不同查詢將不會進行緩存。 SESSION | STATEMENT SESSION
jdbcTypeForNull 當沒有爲參數指定特定的 JDBC 類型時,空值的默認 JDBC 類型。 某些數據庫驅動需要指定列的 JDBC 類型,多數情況直接用一般類型即可,比如 NULL、VARCHAR 或 OTHER。 JdbcType 常量,常用值:NULL、VARCHAR 或 OTHER。 OTHER
lazyLoadTriggerMethods 指定對象的哪些方法觸發一次延遲加載。 用逗號分隔的方法列表。 equals,clone,hashCode,toString
defaultScriptingLanguage 指定動態 SQL 生成使用的默認腳本語言。 一個類型別名或全限定類名。 org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
defaultEnumTypeHandler 指定 Enum 使用的默認 TypeHandler 。(新增於 3.4.5) 一個類型別名或全限定類名。 org.apache.ibatis.type.EnumTypeHandler
callSettersOnNulls 指定當結果集中值爲 null 的時候是否調用映射對象的 setter(map 對象時爲 put)方法,這在依賴於 Map.keySet() 或 null 值進行初始化時比較有用。注意基本類型(int、boolean 等)是不能設置成 null 的。 true | false false
returnInstanceForEmptyRow 當返回行的所有列都是空時,MyBatis默認返回 null。 當開啓這個設置時,MyBatis會返回一個空實例。 請注意,它也適用於嵌套的結果集(如集合或關聯)。(新增於 3.4.2) true | false false
logPrefix 指定 MyBatis 增加到日誌名稱的前綴。 任何字符串 未設置
logImpl 指定 MyBatis 所用日誌的具體實現,未指定時將自動查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 未設置
proxyFactory 指定 Mybatis 創建可延遲加載對象所用到的代理工具。 CGLIB | JAVASSIST JAVASSIST (MyBatis 3.3 以上)
vfsImpl 指定 VFS 的實現 自定義 VFS 的實現的類全限定名,以逗號分隔。 未設置
useActualParamName 允許使用方法簽名中的名稱作爲語句參數名稱。 爲了使用該特性,你的項目必須採用 Java 8 編譯,並且加上 -parameters 選項。(新增於 3.4.1) true | false true
configurationFactory 指定一個提供 Configuration 實例的類。 這個被返回的 Configuration 實例用來加載被反序列化對象的延遲加載屬性值。 這個類必須包含一個簽名爲static Configuration getConfiguration() 的方法。(新增於 3.2.3) 一個類型別名或完全限定類名。 未設置

一個配置完整的 settings 元素的示例如下:

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

6.其他配置

  1. typeHandlers(類型處理器)
  2. objectFactory(對象工廠)
  3. plugins(插件)
    • mybatis-generator-core
    • mybatis-puls
    • 通用mapper

7.映射器

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

方式一:【推薦使用】

​```properties



方式二:

```properties
    <mappers>
<!--        <mapper resource="com/zhang/dao/UserMapper.xml"/>-->
        <mapper class="com.zhang.dao.UserMapper"/>
    </mappers>

​ 使用方式二注意點:

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

方式三:

    <mappers>
<!--        <mapper resource="com/zhang/dao/UserMapper.xml"/>-->
<!--        <mapper class="com.zhang.dao.UserMapper"/>-->
        <package name="com.zhang.dao"/>
    </mappers>

​ 使用方式三注意點:

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

8.結果映射(重點)

   <resultMap id="UserMap" type="user">
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="pwd" property="password"/>
    </resultMap>
    <select id="getUserById" parameterType="int" resultMap="UserMap">
        select * from mybatis.user where id=#{id}
    </select>

resultMap 元素是 MyBatis 中最重要最強大的元素 ,.

ResultMap 的設計思想是,對簡單的語句做到零配置,對於複雜一點的語句,只需要描述語句之間的關係就行了。

8.日誌


8.1日誌工廠

如果一個數據庫操作出現了異常,我們需要排錯,日誌是最好的工具。

曾經sout,debug

現在:日誌工廠!

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-0Qwu3jSs-1589942405751)(C:\Users\張銳的~1\AppData\Local\Temp\1588294711954.png)]

  • SLF4J
  • LOG4J 【掌握】
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING 【掌握】
  • NO_LOGGING

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

STDOUT_LOGGING標準日誌輸出

在MyBatis核心配置文件mybatis-config.xml中,配置我們的日誌!

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

日誌信息:

Opening JDBC Connection
Created connection 1282811396.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4c762604]
==>  Preparing: select * from mybatis.user where id=? 
==> Parameters: 3(Integer)
<==    Columns: id, name, pwd
<==        Row: 3, 王五, 123456
<==      Total: 1
User{id=3, name='王五', pwd='123456'}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4c762604]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4c762604]
Returned connection 1282811396 to pool.

8.2LOG4J

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

1.先導包log4j的包到pom.xml

<dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

2.在resources文件中配置log4j.properties

  1. #將等級爲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/zhang.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.在mybatis-config.xml中配置log4j爲日誌的實現

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

4.log4j的使用

簡單使用

  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");
    

9.分頁

思考:爲什麼要分頁?

  • 減少數據的處理量

9.1使用Limit分頁

語法:SELECT * FROM user LIMIT startIndex,pageSize
SELECT * FROM user LIMIT 3;#[0,n]

使用Mybatis實現分頁,核心sql

  1. 接口

        /**
         * 分頁查詢
         * @param map
         * @return
         */
        List<User> getUserByLimit(Map<String, Integer> map);
    
  2. Mapper.xml

        <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
            select * from mybatis.user limit #{startIndex},#{pageSize}
        </select>
    
  3. 測試

    @Test
    public void getUserLimit(){
        //獲得sqlsession對象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        //        logger.info("進入sql語句查詢-----------------------");
        //執行sql
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
        Map<String, Integer> map=new HashMap<>();
    
        map.put("startIndex",0);
        map.put("pageSize",3);
    
        List<User> user = mapper.getUserByLimit(map);
    
        //打印
        for (User t:user) {
            System.out.println(t);
        }
        //        logger.info("查詢結束--------------------------");
        //關閉sqlsessiopn
        sqlSession.close();
    }
    

9.2RowBounds分頁

瞭解即可

不再使用sql實現分頁

  1. 接口

     /**
         * 分頁查詢2
         * @return
         */
        List<User> getUserByRowBounds();
    
  2. Mapper.xml

    <select id="getUserByRowBounds" resultMap="UserMap">
        select * from mybatis.user
    </select>
    
  3. 測試

    @Test
    public void getUserRowBounds(){
        //獲得sqlsession對象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        //        logger.info("進入sql語句查詢-----------------------");
        //創建RowBounds
        RowBounds bounds = new RowBounds(1,2);
    
        //執行sql
        List<User> user = sqlSession.selectList("com.zhang.dao.UserMapper.getUserByRowBounds",null,bounds);
    
    
        //打印
        for (User t:user) {
            System.out.println(t);
        }
        //        logger.info("查詢結束--------------------------");
        //關閉sqlsessiopn
        sqlSession.close();
    }
    

9.3分頁插件

瞭解即可。

在這裏插入圖片描述

https://pagehelper.github.io/

10.使用註解開發


10.1、面向接口編程

.大家之前都學過面向對象編程,也學習過接口,但在真正的開發中,很多時候我們會選擇面向接口編程
.根本原因: 解耦,可拓展,提高複用,分層開發中,上層不用管具體的實現,大家都遵守共同的標準I使得
開發變得容易,規範性更好
-在一個面向對象的系統中,系統的各種功能是由許許多多的不同對象協作完成的。在這種情況下,各個對象內部
是如何實現自己的,對系統設計人員來講就不那麼重要了;
-而各個對象之間的協作關係則成爲系統設計的關鍵。小到不同類之間的通信,大到各模塊之間的交互,在系統設
計之初都是要着重考慮的,這也是系統設計的主要工作內容。面向接口編程就是指按照這種思想來編程。

關於接口的理解

-接口從更深層次的理解,應是定義(規範,約束)與實現(名實分離的原則)的分離。
.接口的本身反映了系統設計人員對系統的抽象理解。
. 接口應有兩類:
-第一-類是對一個個體的抽象,它可對應爲一一個抽象體(abstract class);
-第二類是對一個個體某- -方面的抽象,即形成一一個抽象面(interface) ;
.-個體有可能有多個抽象面。抽象體與抽象面是有區別的。

三個面向區別

. 面向對象是指,我們考慮問題時,以對象爲單位,考慮它的屬性及方法.
-面向過程是指,我們考慮問題時,以- -個具體的流程(事務過程)爲單位,考慮它的實現.
-接口設計與非接口設計是針對複用技術而言的,與面向對象(過程)不是一一個問題.更多的體現就是對系統整體的
架構

10.2使用註解開發

1.註解在接口上實現

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

2.需要在覈心配置文件綁定接口!

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

3.測試

本質:反射機制實現

低層:動態代理

10.3CRUD

我們可以在工具類JDBC.class創建的時候實現自動提交事務!

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

編寫接口,增加註解!

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

    /**
     * 方法前面存在多個參數,每個參數前加註解@Param
     * @param idd
     * @param namee
     * @return
     */
    @Select("select * from user where id=#{id} and name=#{name}")
    User getUserById(@Param("id") int idd,@Param("name")String namee);

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

    /**
     * 修改
     * @param user
     * @return
     */
    @Update("update user set name=#{name},pwd=#{password} where id=#{id}")
    int updateUser(User user);

    /**
     * 刪除
     * @param uid
     * @return
     */
    @Delete("delete from user where id=#{id}")
    int deleteUser(@Param("id") int uid);

註解的命名和sql語句的命名匹配,否則無法對應取值!

【注意:我們必須要將接口註冊綁定到mybatis-config.xml核心配置中】

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

關於@param()註解

  • 基本類型的參數類型或者String類型,需要加上
  • 引用類型不需要加
  • 如果只有一個基本類型,可以忽略,但是建議加上
  • 我們在sql中引用的就是param中設定的屬性

//#{}防止sql注入,${}不安全

11.Lombok


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

Lombok常用註解說明
●@NonNull: 用在方法參數前,會自動對該參數進行非空校驗,爲空拋出NPE (NullPointerException)
●@Clenup:自動管理資源,用在局部變量之前在當前變量範圍內即將執行完畢退出前會遣理資源 生成-nilly的代碼關閉流
@Gbter/@Setter.用在霸性上,不用自己手寫etterogetter萬法, 還可指定訪問範圍
●@ToSting: 用在類上,可以自動覆寫toString方法
●@EqualsAndHashCode: 用在類上,自動生成equals方法和hashCode方法
@NoArgsConstructor. @RequredArgsConstructor and @AllArgsConstructor:用在類上,自動生成無參構造和使用所有參數的有參構造函數。
●@Data: 用在類上,相當於同時使用了@ToStnng. @EquaisAnarlasnCote. @Getter, @Setter和@RequnedArgsConstrutor這些註解, 對
POJO類十分青用
●@Value: 用在類上,是@Data的不可變形式,相當於爲屬性添加final聲明, 只提供getter方法,而不提供setter方法
@SneakyThrows:自動拋受檢異常.而無需顯式在方法上使用throws語句
●@Synchronized: 用在方法上,將方法聲明爲同步的,並自動加鎖
●@Getter(azy=true): 可以替代經典的Double Check Lock樣板代碼

使用步驟:

  1. 在idea中安裝Lombok插件

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

    <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.12</version>
     </dependency>
    
  3. 在實體類上加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
    

    @Data:無參構造,get,set,hashcode,tostring,equals等方法.

    @AllArgsConstructor有參構造
    @NoArgsConstructor無參構造
    

Lombok的優缺點

優點:
1.能通過註解的形式自動生成構造器、getter/setter. equals. hashcode. toString等方法, 提高了一定的開發效率
2.讓代碼變得簡潔,不用過多的去關注相應的方法
3.屬性做修改時,也簡化了維護爲這些屬性所生成的getter/setter方法等
缺點:
1.不支持多種參數構造器的重載
2.雖然省去了手動創建getter/setter方法的麻煩,但大大降低了源代碼的可讀性和完整性,降低了閱讀源代碼的舒適度

總結

Lombok雖然有很多優點,但L ombok更類似於一種IDE插件, 項目也需要依賴相應的jar包。Lombok依賴jar包是因爲編譯時要用它
的註解,爲什麼說它又類似插件?因爲在使用時,eclipse或Inteli] IDEA都需要安裝相應的插件,在編譯器編譯時通過操作AST (抽象
語法樹)改變字節碼生成,變向的就是說它在改變java語法。

它不像spring的依賴注入或者mybatis的ORM-樣是運行時的特性,而是編譯時的特性。這裏我個人最感覺不爽的地方就是對插件的
依賴!因爲Lombok只是省去了一些人工生成代碼的麻煩,但IDE都有快捷鍵來協助生成getter/setter等方法,也非常方便。

知乎上有位大神發表過對Lombok的一-些看法:
這是一一種低級趣味的插件,不建議使用。JAVA發展到今天,各種插件層出不窮,如何甄別各種插件的優劣?能從架構上優化你的設計的,能提高應用程序性能的,實現高度封裝可擴展的…像lombok這種, 像這種插件,已經不僅僅是插件了,改變了你如何編寫源碼,事實上,少去了的代碼,
你寫上去又如何?如果JAVA家族到處充斥這樣的東西, 那隻不過是一坨披着金屬顏色的屎,遲早會被其它的語言取代。

12.多對一處理


在這裏插入圖片描述

  • 多個學生,對應一個老師
  • 對於學生而言,關聯。。多個學生關聯一個老師
  • 對於老師而言,集合。。一個老師有很多學生

SQL語句:

CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老師');

CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小紅', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小張', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

測試環境搭建

  1. 導入lombok
  2. 新建實體類Teacher,Student
  3. 建立Mapper接口
  4. 建立Mapper.xml文件
  5. 在覈心配置文件中綁定註冊Mapper接口或文件
  6. 測試查詢是否成功!

按照查詢嵌套處理

<!--
思路:
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="getStudent2" resultMap="ST">
        SELECT s.id sid,s.name sname,t.name tname
        FROM student s,teacher t
        where s.tid=t.id;
    </select>

    <resultMap id="ST" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="Teacher">
            <result property="name" column="tname"/>
        </association>
    </resultMap>

回顧Mysql多對一查詢方式:

  • 子查詢
  • 連表查詢

13.一對多處理


比如一個老師擁有多個學生

對老師而言,就是一對多

1.環境搭建

實體類

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

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

按照結果嵌套處理

    <select id="getTeacher2" parameterType="int" resultMap="TS">
        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="TS" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="sid"/>
        </collection>
    </resultMap>

按照查詢嵌套處理

    <select id="getTeacher1" resultMap="TtSs">
        select * from teacher where id=#{tid}
    </select>
    
    <resultMap id="TtSs" type="Teacher">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudent"/>
    </resultMap>

    <select id="getStudent" resultType="Student">
        select * from student where tid=#{tid}
    </select>

小結

1.關聯-association【多對一】

2.集合-collection【一對多】

3.javaType & ofType

  1. javaType用來指定實體類中屬性類型
  2. ofType用來指定映射到List或pojo類型中,泛型的約束類型!

4.注意點

  • 保證SQL的可讀性,儘量保證通俗易懂!
  • 注意一對多和多對一中,屬性名和字段問題
  • 如果問題不好排查,建議使用日誌

14.動態SQL


什麼是動態SQL:動態SQL就是指根據不同的條件生成不同的SQL語句
利用動態SQL這一特性可以徹底擺脫這種痛苦。

動態SQL元素和JSTL或基於類似XML的文本處理器相似。在MyBatis 之前的版本中,有很多元素需要花時間瞭解。MyBatis 3大大精簡了元素種類,現在只需學習原來一-半的元素便可。MyBatis 採用功能強大的基於OGNL的表達式來淘汰其它大部分元素。
if
choose (when, otherwise)
trim (where, set)
foreach

搭建環境:

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客標題',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '創建時間',
`views` INT(30) NOT NULL COMMENT '瀏覽量'
)ENGINE=INNODB DEFAULT CHARSET=utf8

創建一個基礎工程

  1. 導包

  2. 編寫配置文件

  3. 編寫實體類

    @Data
    public class Blog {
        private int id;
        private String title;
        private String author;
        private Date createTime;
        private int views;
    }
    
  4. 編寫實體類對應Mapper接口和Mapper.xml

    public interface BlogMapper {
    
        //插入數據
        int addBlog(Blog blog);
    }
    
    <?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.zhang.dao.BlogMapper">
        <insert id="addBlog" parameterType="blog">
            insert into mybatis.blog (id,title,author,create_time,views)
            values (#{id},#{title},#{author},#{createTime},#{views});
        </insert>
    </mapper>
    

if

這條語句提供了可選的查找文本功能。如果不傳入 “title”,那麼所有處於 “ACTIVE” 狀態的 BLOG 都會返回;如果傳入了 “title” 參數,那麼就會對 “title” 一列進行模糊查找並返回對應的 BLOG 結果(細心的讀者可能會發現,“title” 的參數值需要包含查找掩碼或通配符字符)。

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

choose、when、otherwise

有時候,我們不想使用所有的條件,而只是想從多個條件中選擇一個使用。針對這種情況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句。

還是上面的例子,但是策略變爲:傳入了 “title” 就按 “title” 查找,傳入了 “author” 就按 “author” 查找的情形。若兩者都沒有傳入,就返回標記爲 featured 的 BLOG(這可能是管理員認爲,與其返回大量的無意義隨機 Blog,還不如返回一些由管理員挑選的 Blog)。

  <select id="queryChoose" resultType="blog" parameterType="map">
        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>

trim、where、set

where 元素只會在子元素返回任何內容的情況下才插入 “WHERE” 子句。而且,若子句的開頭爲 “AND” 或 “OR”,where 元素也會將它們去除。

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

用於動態更新語句的類似解決方案叫做 setset 元素可以用於動態包含需要更新的列,忽略其它不更新的列。比如:

<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 關鍵字,並會刪掉額外的逗號(這些逗號是在使用條件語句給列賦值時引入的)。

總結

所謂動態sql,本質是sql,只是在sql層面增加了邏輯代碼。

SQL片段


有時候,我們會抽取一些代碼,方便複用!

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

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

       <select id="queryBlogIF" parameterType="map" resultType="blog">
            select * from blog
            <where>
                <include refid="ift"></include>
            </where>
        </select>
    

注意事項:

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

Foreach


select * from user where 1=1 and 
(id=1 or id=2 or id=3)

  <foreach item="id" collection="ids"
      open="(" separator="or" close=")">
        #{id}
  </foreach>

在這裏插入圖片描述

    <select id="queryBlogForeach" parameterType="map" resultType="Blog">
        select * from blog
        <where>
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                id = #{id}
            </foreach>
        </where>
    </select>
    //查詢第1-2-3號記錄的博客
    List<Blog> queryBlogForeach(Map map);

    @Test
    public void queryBlogForeach(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();

        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        Map map = new HashMap();

        ArrayList<Integer> list = new ArrayList();

        list.add(1);
        list.add(2);
        list.add(3);

        map.put("ids",list);

        List<Blog> blogs = mapper.queryBlogForeach(map);

        for (Blog blog : blogs) {
            System.out.println(blog);
        }

        sqlSession.close();
    }

總結:

動態·sql就是在拼接sql語句,我們只需要保證sql的正確性。按照sql的格式去排列組合就可以。

建議:

  • 先在mysql中寫出完整的sql,再去對應修改成動態sql。

15.緩存


15.1簡介

查詢	: 連接數據庫	,耗資源	,優化
一次查詢結果,暫存在可以取到的資源-->內存	:	緩存
我們再次查詢相同數據,直接走緩存,不用走數據庫。

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

2.爲什麼使用緩存?
。減少和數據庫的交互次數,減少系統開銷,提高系統效率。

3.什麼樣的數據能使用緩存?
。經常查詢並且不經常改變的數據。【可以使用緩存】

15.2、Mybatis緩存

●MyBatis包含一個非常強大的查詢緩存特性, 它可以非常方便地定製和配置緩存。緩存可以極大的提升查詢效

●MyBatis系統中默認定義了兩級緩存: 一級緩存二級緩存
默認情況下,只有一 級緩存開啓。 (SqISession級別的緩存, 也稱爲本地緩存)
二級緩存需要手動開啓和配置,他是基於namespace級別的緩存。
爲了提高擴展性,MyBatis定義 了緩存接口Cache。我們可以通過實現Cache接口來自定義二級緩存

15.3一級緩存


●- -級緩存也叫本地緩存: SqlSession
。與數據庫同-次會話期間查詢到的數據會放在本地緩存中。
。以後如果需要獲取相同的數據,直接從緩存中拿,沒必須再去查詢數據庫;

測試步驟:

  1. 開啓日誌

        <settings>
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
    
  2. 測試在一個Session中查詢兩次

       @Test
        public void te(){
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
    
            User user1 = mapper.queryUserById(2);
            System.out.println(user1);
    
            System.out.println("===================");
            User user2 = mapper.queryUserById(2);
            System.out.println(user2);
    
            System.out.println(user1==user2);
    
            sqlSession.close();
        }
    
  3. 查看日誌輸出

    Opening JDBC Connection
    Created connection 22805895.
    ==>  Preparing: select * from user WHERE id = ? 
    ==> Parameters: 2(Integer)
    <==    Columns: id, name, pwd
    <==        Row: 2, 小朋友, 333
    <==      Total: 1
    User(id=2, name=小朋友, pwd=333)
    ===================
    User(id=2, name=小朋友, pwd=333)
    true
    Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@15bfd87]
    Returned connection 22805895 to pool.
    

緩存失效的情況:

  1. 查詢不同東西

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

    Opening JDBC Connection
    Created connection 1475491159.
    ==>  Preparing: select * from user WHERE id = ? 
    ==> Parameters: 2(Integer)
    <==    Columns: id, name, pwd
    <==        Row: 2, 小朋友, 333
    <==      Total: 1
    User(id=2, name=小朋友, pwd=333)
    ==>  Preparing: update user set name = ?,pwd=? where id=?; 
    ==> Parameters: 測試(String), 23123(String), 3(Integer)
    <==    Updates: 1
    ===================
    ==>  Preparing: select * from user WHERE id = ? 
    ==> Parameters: 2(Integer)
    <==    Columns: id, name, pwd
    <==        Row: 2, 小朋友, 333
    <==      Total: 1
    User(id=2, name=小朋友, pwd=333)
    false
    Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@57f23557]
    Returned connection 1475491159 to pool.
    
  3. 查詢不同的Mapper.xml

  4. 手動清除緩存

        @Test
        public void te(){
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
    
            User user1 = mapper.queryUserById(2);
            System.out.println(user1);
    
    //        mapper.updateUser(new User(3,"測試","23123"));
            //手動清理緩存
            sqlSession.clearCache();
    
            System.out.println("===================");
            User user2 = mapper.queryUserById(2);
            System.out.println(user2);
    
            System.out.println(user1==user2);
    
            sqlSession.close();
        }
    

小結:一級緩存默認開啓,只在依次Session中有效!

15.4二級緩存


●二級緩存也叫全局緩存,一級緩存作用域太低了,所以誕生了二級緩存

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

●工作機制
。-一個會話查詢一 條數據,這個數據就會被放在當前會話的一級緩存中;
。如果當前會話關閉了,這個會話對應的一級緩存就沒了;但是我們想要的是,會話關閉了,- -級緩存中的
數據被保存到二級緩存中;
。新的會話查詢信息,就可以從二級緩存中獲取內容;
。不同的mapper查出的數據會放在自己對應的緩存(map) 中;

步驟:

  1. 開啓全局緩存

            <setting name="cacheEnabled" value="true"/>
    
  2. 在要使用二級緩存的Mapper中開啓

        <cache/>
    

    也可以自定義參數

        <cache
            eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"
        />
    
  3. 測試

    1.問題:我們需要將實體類序列化!否則就會報錯!
    Caused by: java. io. NotSerializableException: com. kuang. pojo.user

    Opening JDBC Connection
    Created connection 450003680.
    ==>  Preparing: select * from user WHERE id = ? 
    ==> Parameters: 2(Integer)
    <==    Columns: id, name, pwd
    <==        Row: 2, 小朋友, 333
    <==      Total: 1
    User(id=2, name=小朋友, pwd=333)
    ===================
    Cache Hit Ratio [com.zhang.dao.UserMapper]: 0.0
    User(id=2, name=小朋友, pwd=333)
    true
    Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1ad282e0]
    Returned connection 450003680 to pool.
    

    小結:

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

15.5緩存原理圖


在這裏插入圖片描述

自定義緩存:

Ehcache是一種廣泛使用的開源java分佈式緩存。

要在程序中使用,先要導報到pom.xml文件中

       <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.1.0</version>
        </dependency>

在Mapper.xml中指定使用的cache

  <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

ehcache.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">

    <diskStore path="./tmpdir/Tmp_EhCache"/>

    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
</ehcache>

主流緩存:

redis等

小結

| 此筆記是博主在學習了狂神說教程後整理的,如有需要的小夥伴可私信博主,博主分享給你。另附上學習教程視頻資源:

鏈接: https://www.bilibili.com/video/BV1NE411Q7Nx.
如果整理過程中博主有理解不對的地方,歡迎各位小夥伴留言指正,博主一定虛心接受並改正!
如果覺得博主的學習筆記對你有所幫助,可以給博主點一個贊👍

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章