最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MyBatis延遲加載與多級緩存全解析

 更新時間:2025年09月29日 11:25:26   作者:期待のcode  
文章介紹MyBatis的延遲加載與多級緩存機制,延遲加載按需加載關(guān)聯(lián)數(shù)據(jù)提升性能,一級緩存會話級默認(rèn)開啟,二級緩存工廠級支持跨會話共享,增刪改操作會清空對應(yīng)緩存,確保數(shù)據(jù)一致性,感興趣的朋友跟隨小編一起看看吧

MyBatis延遲加載策略

在 MyBatis 中,延遲加載(Lazy Loading) 是一種按需加載數(shù)據(jù)的機制,指在查詢主對象時,不立即加載其關(guān)聯(lián)的子對象(或關(guān)聯(lián)數(shù)據(jù)),而是等到真正需要使用這些關(guān)聯(lián)數(shù)據(jù)時,才發(fā)起數(shù)據(jù)庫查詢?nèi)ゼ虞d。這種機制的核心目的是減少不必要的數(shù)據(jù)庫交互,提高系統(tǒng)性能,尤其適用于關(guān)聯(lián)關(guān)系復(fù)雜或關(guān)聯(lián)數(shù)據(jù)量大的場景。

延遲加載主要用于關(guān)聯(lián)查詢,即通過resultMap中 <association>(一對一)或 <collection>(一對多)配置的關(guān)聯(lián)對象。

立即加載和延遲加載的區(qū)別,使用一對多的環(huán)境舉例子。
立即加載:當(dāng)前查詢用戶的時候,默認(rèn)也把該用戶所擁有的帳戶信息查詢出來;
延遲加載:當(dāng)前查詢用戶的時候,沒有把該用戶所擁有的帳戶信息查詢出來,而是使用帳戶數(shù)據(jù)的時候,再去查詢賬戶的數(shù)據(jù)。

一對多示例

編寫 JavaBean

import java.io.Serializable;
public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    // 添加用戶屬性
    private User user;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public Integer getUid() {
        return uid;
    }
    public void setUid(Integer uid) {
        this.uid = uid;
    }
    public Double getMoney() {
        return money;
    }
    public void setMoney(Double money) {
        this.money = money;
    }
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", uid=" + uid +
                ", money=" + money +
                ", user=" + user +
                '}';
    }
}
package com.qcby.domain;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class User implements Serializable {
    //主鍵
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    // 存儲所有的id
    private List<Integer> ids;
    // 一個用戶擁有多個賬戶(演示一對多查詢)
    private List<Account> accounts;
    // 一個用戶擁有多個角色(演示多對多查詢)
    private List<Role> roles;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public List<Integer> getIds() {
        return ids;
    }
    public void setIds(List<Integer> ids) {
        this.ids = ids;
    }
    public List<Account> getAccounts() {
        return accounts;
    }
    public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }
    public List<Role> getRoles() {
        return roles;
    }
    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                ", ids=" + ids +
                ", accounts=" + accounts +
                ", roles=" + roles +
                '}';
    }
}

SqlMapConfig_lazy.xml 中開啟延遲加載(lazyLoadingEnabled),以及將積極加載(aggressive lazy loading)改為消極加載(按需加載)

<?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>
    <settings>
        <!-- 開啟延遲加載 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 將積極加載改為消極加載/按需加載 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    <!-- 配置環(huán)境 -->
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis_db"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 加載映射的配置文件 -->
    <mappers>
        <mapper resource="mappers/AccountMapper.xml"/>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>

在AccountMapper.java接口內(nèi)編寫方法

import com.qcby.domain.Account;
import java.util.List;
public interface AccountMapper {
    public List<Account> findAccountAll();
    public List<Account> findAccountAllLazy();
}

編寫AccountMapper.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.qcby.mapper.AccountMapper">
    <!--內(nèi)連接查詢-->
    <select id="findAccountAll" resultMap="accountMap">
        select a.*,u.username,u.sex from account as a, user as u where a.uid=u.id;
    </select>
    <!--配置resultMap標(biāo)簽 目的是進(jìn)行數(shù)據(jù)封裝-->
    <resultMap id="accountMap" type="com.qcby.domain.Account">
        <result property="id" column="id"/>
        <result property="uid" column="uid"/>
        <result property="money" column="money"/>
        <association property="user" javaType="com.qcby.domain.User">
            <result property="username" column="username" />
            <result property="sex" column="sex" />
        </association>
    </resultMap>
    <!--延遲加載-->
    <select id="findAccountAllLazy" resultMap="accountlazyMap">
        SELECT * FROM account;
    </select>
    <resultMap id="accountlazyMap" type="com.qcby.domain.Account">
        <result property="id" column="id"/>
        <result property="uid" column="uid"/>
        <result property="money" column="money"/>
        <!--配置多對一的延遲加載(Account關(guān)聯(lián)的user集合,對user屬性進(jìn)行數(shù)據(jù)封裝)-->
        <association property="user" javaType="com.qcby.domain.User" column="uid" select="com.qcby.mapper.UserMapper.findById" fetchType="lazy"/>
    </resultMap>
</mapper>

在 resultMap 的關(guān)聯(lián)標(biāo)簽中配置延遲加載:
column=“uid” 即查詢user時需要傳遞的參數(shù),select=“com.qcby.mapper.UserMapper.findById” 指定加載user對象時要調(diào)用的SQL語句,fetchType 屬性是延遲加載的局部配置方式,lazy表示延遲加載、eager立即加載,fetchType="lazy"只有明確訪問關(guān)聯(lián)對象的屬性時才會觸發(fā)關(guān)聯(lián)對象的加載,進(jìn)一步減少不必要的數(shù)據(jù)庫查詢。

其中 UserMapper.findById 的查詢語句如下:

測試方法

import com.qcby.domain.Account;
import com.qcby.mapper.AccountMapper;
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 org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class UserTest_lazy {
    @Test
    public void testfindRoleALL(){
        try {
            InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig_lazy.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession session = factory.openSession();
            AccountMapper mapper = session.getMapper(AccountMapper.class);
            List<Account> accounts = mapper.findAccountAll();
            for (Account account : accounts) {
                System.out.println(account);
                System.out.println(account.getMoney());
                System.out.println(account.getUser().getUsername());
                System.out.println("==============");
            }
            //關(guān)閉資源
            session.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 測試延遲加載的測試方法
     */
    @Test
    public void testfindAccountlazyALL(){
        try {
            InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig_lazy.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession session = factory.openSession();
            AccountMapper mapper = session.getMapper(AccountMapper.class);
            List<Account> list = mapper.findAccountAllLazy();
            for (Account account : list) {
                System.out.println(account.getMoney());
                //System.out.println(account.getUser().getUsername());
                System.out.println("=============================");
                System.out.println("");
            }
            //關(guān)閉資源
            session.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

實現(xiàn)效果:

運行 testfindRoleALL() 方法,立即加載,通過內(nèi)連接一次性查詢賬戶和關(guān)聯(lián)的用戶信息

運行 testfindAccountlazyALL() 方法,延遲加載,先查詢賬戶信息,當(dāng)需要用戶信息時再單獨查詢,減少不必要的數(shù)據(jù)庫交互

輸出 user.getUsername() 時,不會觸發(fā)關(guān)聯(lián)對象的加載,只執(zhí)行 SELECT * FROM account;

輸出 user.getAccounts().size() 時,第一步固定執(zhí)行查詢所有賬戶信息 SELECT * FROM account;,訪問到Account對象的user屬性觸發(fā)延遲加載,第二步執(zhí)行子查詢語句 select * from user where id = ?; ,其中?會被替換為傳入的column="uid"的具體賬戶的uid值

一對多示例

UserMapper.java 接口添加方法

import com.qcby.domain.User;
import java.util.List;
public interface UserMapper {
    //一對多延遲加載查詢
    public List<User> findUserAllLazy();
}

UserMapper.xml 配置文件中添加

    <!-- 一對多延遲加載 -->
    <select id="findUserAllLazy" resultMap="UserAlllazy">
        SELECT * FROM  user;
    </select>
    <resultMap id="UserAlllazy" type="com.qcby.domain.User">
        <result property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="birthday" column="birthday"/>
        <result property="sex" column="sex"/>
        <result property="address" column="address"/>
        <!-- 配置一對多的延遲加載(User關(guān)聯(lián)的accounts集合,對accounts屬性進(jìn)行數(shù)據(jù)封裝)-->
        <collection property="accounts" ofType="com.qcby.domain.Account" column="id" select="com.qcby.mapper.AccountMapper.findAccountById" fetchType="lazy"/>
    </resultMap>

AccountMapper.xml 配置文件中添加

    <!-- 根據(jù)用戶id(uid)查詢該用戶的所有賬戶 -->
    <select id="findAccountById" parameterType="int" resultType="com.qcby.domain.Account">
        SELECT  * FROM account where uid=#{uid};
    </select>

SqlMapConfig_lazy.xml 配置文件內(nèi)容不變

<?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>
    <settings>
        <!-- 開啟延遲加載 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 將積極加載改為消極加載/按需加載 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    <!-- 配置環(huán)境 -->
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis_db"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 加載映射的配置文件 -->
    <mappers>
        <mapper resource="mappers/AccountMapper.xml"/>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>

測試方法

import com.qcby.domain.Account;
import com.qcby.domain.User;
import com.qcby.mapper.AccountMapper;
import com.qcby.mapper.UserMapper;
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 org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class UserTest_lazy {
    @Test
    public void testfindUserlazyALL(){
        try {
            InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig_lazy.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession session = factory.openSession();
            UserMapper mapper = session.getMapper(UserMapper.class);
            List<User> list = mapper.findUserAllLazy();
            for (User user : list) {
                System.out.println(user.getUsername());
                //System.out.println(user.getAccounts().size());
                System.out.println("=============================");
                System.out.println("");
            }
            //關(guān)閉資源
            session.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

實現(xiàn)效果:

輸出 user.getUsername() 時,不會觸發(fā)關(guān)聯(lián)對象的加載,只執(zhí)行 SELECT * FROM user;

輸出 user.getAccounts().size() 時,第一步固定執(zhí)行查詢所有用戶信息 SELECT * FROM user;,訪問到User對象的accounts屬性觸發(fā)延遲加載,第二步執(zhí)行子查詢語句 SELECT * FROM account where uid = ?; ,其中?會被替換為傳入的column="id"的具體用戶的id值

MyBatis框架的緩存

緩存是指在計算系統(tǒng)中,通過特定的高速存儲介質(zhì)臨時存儲數(shù)據(jù)源中頻繁訪問的數(shù)據(jù)副本,以實現(xiàn)數(shù)據(jù)快速復(fù)用的機制。其核心原理是利用高速存儲介質(zhì)與數(shù)據(jù)源之間的訪問速度差異,當(dāng)數(shù)據(jù)請求發(fā)生時,優(yōu)先從緩存中查詢目標(biāo)數(shù)據(jù):若緩存中存在該數(shù)據(jù),則直接返回緩存副本,避免對原始數(shù)據(jù)源的訪問;若緩存中不存在該數(shù)據(jù),則從數(shù)據(jù)源獲取數(shù)據(jù)并同步至緩存,為后續(xù)可能的重復(fù)請求提供基礎(chǔ)。
這種機制通過縮短數(shù)據(jù)訪問路徑、降低對低速數(shù)據(jù)源的依賴,有效提升了系統(tǒng)響應(yīng)速度與整體吞吐量,是計算機領(lǐng)域優(yōu)化數(shù)據(jù)訪問性能的核心技術(shù)之一。

一級緩存

MyBatis 的一級緩存,官方稱其為本地緩存(Local Cache),是框架默認(rèn)啟用且無需額外配置的會話級緩存機制,其作用域嚴(yán)格限定在單個 SqlSession 實例的生命周期內(nèi)。在實現(xiàn)層面,每個 SqlSession 對象內(nèi)部維護(hù)著一個基于 Map 的鍵值對集合,專門用于存儲緩存數(shù)據(jù)。

其工作流程遵循緩存優(yōu)先原則:當(dāng)通過當(dāng)前 SqlSession 執(zhí)行查詢操作時,MyBatis 會先在一級緩存中進(jìn)行檢索,若緩存中存在對應(yīng)數(shù)據(jù),則直接返回該緩存副本,無需與數(shù)據(jù)庫交互;若緩存中不存在目標(biāo)數(shù)據(jù),則執(zhí)行數(shù)據(jù)庫查詢,獲取結(jié)果后,會自動將該結(jié)果存入當(dāng)前 SqlSession 的一級緩存中,為后續(xù)相同條件的查詢提供數(shù)據(jù)支持。

為保障緩存數(shù)據(jù)與數(shù)據(jù)庫數(shù)據(jù)的一致性,一級緩存會被自動維護(hù):當(dāng)在當(dāng)前 SqlSession 中執(zhí)行 INSERT、UPDATE、DELETE 等寫操作時,MyBatis 會觸發(fā)一級緩存的清空機制,避免因數(shù)據(jù)更新導(dǎo)致緩存中留存舊數(shù)據(jù);當(dāng) SqlSession 執(zhí)行關(guān)閉、提交或回滾操作時,其對應(yīng)的一級緩存也會隨之失效并釋放資源。

這種機制使得一級緩存僅在單個數(shù)據(jù)庫會話內(nèi)有效,不同 SqlSession 之間的緩存相互隔離、無法共享,從而在減少同一會話內(nèi)重復(fù)查詢的數(shù)據(jù)庫訪問次數(shù)的同時,避免了跨會話的數(shù)據(jù)一致性風(fēng)險。

SqlMapConfig_cache.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>
    <!-- 配置環(huán)境 -->
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis_db"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 加載映射的配置文件 -->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>

需要注意的是,為比較輸出對象的是否為同一對象,我們比較輸出對象的引用地址,即 User 類不重寫 toString() 方法

測試方法

import com.qcby.domain.User;
import com.qcby.mapper.UserMapper;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class UserTest_cache {
    /**
     * 證明一級緩存的存在
     */
    @Test
    public void run1() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig_cache.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = factory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //通過主鍵查詢
        User user = mapper.findById(1);
        System.out.println(user);
        System.out.println("==================================");
        //手動清空緩存
        //sqlSession.clearCache();
        //再查詢一次
        User user1=mapper.findById(1);
        System.out.println(user1);
        sqlSession.close();
        inputStream.close();
    }
}

盡管進(jìn)行了兩次查詢,但日志中僅出現(xiàn)了一條 SQL 語句的執(zhí)行記錄,且兩次查詢輸出的User對象引用地址完全相同,這說明第二次查詢并未重新執(zhí)行 SQL 去數(shù)據(jù)庫獲取數(shù)據(jù),而是直接復(fù)用了第一次查詢后緩存到內(nèi)存中的User對象,符合一級緩存緩存主線程同一會話中相同查詢條件的結(jié)果的特性。

執(zhí)行 sqlSession.clearCache();,手動清空緩存,這樣日志出現(xiàn)了兩條SQL語句,且兩次查詢輸出的User對象引用地址不同

import com.qcby.domain.User;
import com.qcby.mapper.UserMapper;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class UserTest_cache {
    @Test
    public void run2() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig_cache.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = factory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.findById(1);
        System.out.println(user);
        System.out.println("==================================");
        SqlSession sqlSession1 = factory.openSession();
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        User user1=mapper1.findById(1);
        System.out.println(user1);
        sqlSession.close();
        inputStream.close();
    }
}

兩次查詢分別在兩個獨立的SqlSession實例中執(zhí)行,而 MyBatis 的一級緩存作用域嚴(yán)格限定于單個SqlSession,這兩個會話各自維護(hù)一個獨立且初始為空的緩存。因此,第一次查詢命中第一個SqlSession的空緩存,觸發(fā)數(shù)據(jù)庫訪問并生成一條 SQL 日志,結(jié)果存入該會話的緩存;第二次查詢同樣命中第二個SqlSession的空緩存,再次觸發(fā)數(shù)據(jù)庫訪問并生成第二條 SQL 日志,結(jié)果存入第二個會話的緩存。由于兩次查詢返回的是兩個不同的User對象實例,因此它們的哈希碼標(biāo)識不同。這一現(xiàn)象清晰地證明了一級緩存的會話隔離性,即緩存數(shù)據(jù)無法在不同SqlSession之間共享。

二級緩存

MyBatis 的二級緩存是 SqlSessionFactory 級別的緩存,它在查詢時優(yōu)先被檢查,如果命中則直接返回數(shù)據(jù);若未命中,則繼續(xù)檢查當(dāng)前 SqlSession 的一級緩存,仍未命中才查詢數(shù)據(jù)庫,并將結(jié)果先寫入一級緩存,待 SqlSession 關(guān)閉或提交時,再將一級緩存中的數(shù)據(jù)同步到二級緩存中,供其他 SqlSession 共享。同時,為保證數(shù)據(jù)一致性,當(dāng)同一 Namespace 內(nèi)執(zhí)行任何增、刪、改操作時,該 Namespace 下的整個二級緩存會被自動清空,從而避免讀取到臟數(shù)據(jù)。

SqlMapConfig_cache.xml 中添加如下配置開啟全局緩存開關(guān)

    <settings>
        <!--開啟二級緩存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

UserMapper.xml 中開啟二級緩存,表示該Mapper的Namespace將啟用二級緩存

    <!--開啟二級緩存使用-->
    <cache/>
package com.qcby;
import com.qcby.domain.User;
import com.qcby.mapper.UserMapper;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class UserTest_cache {
    @Test
    public void run3() throws IOException {
        //加載配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig_cache.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = factory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.findById(1);
        System.out.println(user);
        System.out.println("=====================");
        //手動清空一級緩存
        sqlSession.clearCache();
        sqlSession.commit();
        //關(guān)閉session
        sqlSession.close();
        SqlSession sqlSession1=factory.openSession();
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        User user1=mapper1.findById(1);
        System.out.println(user1);
        sqlSession1.close();
        inputStream.close();
    }
}

第一個SqlSession執(zhí)行查詢時,因二級緩存和自身一級緩存均為空,故訪問數(shù)據(jù)庫并生成SQL日志,查詢結(jié)果存入一級緩存;在其commit并close后,MyBatis將結(jié)果序列化并寫入UserMapper對應(yīng)的二級緩存。第二個SqlSession執(zhí)行相同查詢時,直接命中二級緩存,因此沒有SQL日志輸出,且控制臺打印出“Cache Hit Ratio”表明緩存命中率,證明了跨SqlSession的數(shù)據(jù)共享;由于從二級緩存中獲取數(shù)據(jù)時,進(jìn)行了反序列化操作,生成的是一個全新的對象,而不是第一個SqlSession中的那個對象實例,所以兩次打印的User對象哈希碼不同。

UserMapper.xml 配置文件中設(shè)置如下內(nèi)容

    <select id="findById" resultType="com.qcby.domain.User" parameterType="int" useCache="false">
        select * from user where id = #{id};
    </select>

useCache 屬性用于控制當(dāng)前查詢是否使用二級緩存,當(dāng)Mapper.xml文件通過<cache>標(biāo)簽開啟了二級緩存后,該文件中所有的<select>語句默認(rèn)繼承此設(shè)置,即 useCache=“true”。設(shè)置 useCache=“false” 即禁用當(dāng)前這條查詢語句的二級緩存功能,MyBatis 在執(zhí)行查詢時,會完全跳過二級緩存的檢查,直接去查詢一級緩存。

需要注意的是如果沒有讓 User 類實現(xiàn) Serializable 序列化接口,會拋出 NotSerializableException 異常

到此這篇關(guān)于MyBatis框架—延遲加載與多級緩存的文章就介紹到這了,更多相關(guān)MyBatis延遲加載與多級緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決Maven項目報錯:failed?to?execute?goal?org.apache.maven.plugins:maven-compiler-plugin:3.13.0的問題

    解決Maven項目報錯:failed?to?execute?goal?org.apache.maven.plug

    這篇文章主要介紹了解決Maven項目報錯:failed?to?execute?goal?org.apache.maven.plugins:maven-compiler-plugin:3.13.0的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • Java獲取視頻時長和封面截圖

    Java獲取視頻時長和封面截圖

    這篇文章主要為大家詳細(xì)介紹了如何使用Java獲取視頻時長和封面截圖功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-03-03
  • java操作文件之文件重命名實現(xiàn)方式

    java操作文件之文件重命名實現(xiàn)方式

    這篇文章主要介紹了java操作文件之文件重命名實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2026-03-03
  • Java中刪除文件或文件夾的幾種方法總結(jié)

    Java中刪除文件或文件夾的幾種方法總結(jié)

    這篇文章主要介紹了Java中刪除文件或文件夾的幾種方法總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Java Swing中JDialog實現(xiàn)用戶登陸UI示例

    Java Swing中JDialog實現(xiàn)用戶登陸UI示例

    這篇文章主要介紹了Java Swing中JDialog實現(xiàn)用戶登陸UI功能,結(jié)合完整實例形式分析了Swing使用JDialog實現(xiàn)用戶登陸UI界面窗口功能的步驟與相關(guān)操作技巧,需要的朋友可以參考下
    2017-11-11
  • 使用JMX監(jiān)控Zookeeper狀態(tài)Java API

    使用JMX監(jiān)控Zookeeper狀態(tài)Java API

    今天小編就為大家分享一篇關(guān)于使用JMX監(jiān)控Zookeeper狀態(tài)Java API,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • JDBC的擴展知識點總結(jié)

    JDBC的擴展知識點總結(jié)

    這篇文章主要介紹了JDBC的擴展知識點總結(jié),文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)JDBC的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • Spring中的FactoryBean與BeanFactory詳細(xì)解析

    Spring中的FactoryBean與BeanFactory詳細(xì)解析

    這篇文章主要介紹了Spring中的FactoryBean與BeanFactory詳細(xì)解析,在Spring框架中,FactoryBean和BeanFactory是兩個關(guān)鍵的接口,用于創(chuàng)建和管理對象實例,它們在Spring的IoC(Inversion of Control,控制反轉(zhuǎn))容器中發(fā)揮著重要的作用,需要的朋友可以參考下
    2023-11-11
  • Jackson序列化和反序列化忽略字段操作

    Jackson序列化和反序列化忽略字段操作

    這篇文章主要介紹了Jackson序列化和反序列化忽略字段操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • java執(zhí)行字符串公式的三種方法總結(jié)

    java執(zhí)行字符串公式的三種方法總結(jié)

    Java是一種廣泛應(yīng)用的編程語言,字符串邏輯運算是Java編程中一個非常重要的方面,這篇文章主要介紹了java執(zhí)行字符串公式的三種方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-07-07

最新評論

荆州市| 塔河县| 祁连县| 杨浦区| 新营市| 宜阳县| 永嘉县| 子洲县| 宜城市| 万山特区| 论坛| 同心县| 汽车| 民县| 论坛| 公主岭市| 丽江市| 大田县| 永嘉县| 湄潭县| 攀枝花市| 大田县| 革吉县| 肥乡县| 沁源县| 磴口县| 西林县| 神池县| 巴林右旗| 凌海市| 陈巴尔虎旗| 新兴县| 望谟县| 陆丰市| 南丹县| 通辽市| 彩票| 安义县| 沧源| 当阳市| 凯里市|