day09-MyBatis緩存

来源:https://www.cnblogs.com/liyuelian/archive/2023/03/03/17177177.html
-Advertisement-
Play Games

MyBatis緩存 mybatis – MyBatis 3 | cache MyBatis 一級緩存全詳解(一) MyBatis 內置了一個強大的事務性查詢緩存機制,它可以非常方便地配置和定製。 為了使它更加強大而且易於配置,我們對 MyBatis 3 中的緩存實現進行了許多改進。 1.一級緩存 1 ...


MyBatis緩存

mybatis – MyBatis 3 | cache

MyBatis 一級緩存全詳解(一)

MyBatis 內置了一個強大的事務性查詢緩存機制,它可以非常方便地配置和定製。 為了使它更加強大而且易於配置,我們對 MyBatis 3 中的緩存實現進行了許多改進。

1.一級緩存

1.1基本說明

Mybatis的一級緩存(也叫本地緩存/Local Cache)是指SqlSession級別的,作用域是SqlSession。

Mybatis預設開啟一級緩存,在同一個SqlSession中,相同的Sql查詢的時候,第一次查詢的時候,就會從緩存中取,如果發現沒有數據,那麼就從資料庫查詢出來,並且緩存到HashMap中,如果下次還是相同的查詢,就直接從緩存中查詢,就不在去查詢資料庫,對應的就不在去執行SQL語句。

當查詢到的數據,進行增刪改的操作的時候,緩存將會失效。在spring容器管理中每次查詢都是創建一個新的sqlSession,所以在分散式環境中不會出現數據不一致的問題。

一級緩存原理圖:

image-20230302185156341

在參數和SQL完全一樣的情況下,我們使用同一個SqlSession對象調用一個Mapper方法,往往只執行一次SQL,因為使用SelSession第一次查詢後,MyBatis會將其放在緩存中,以後再查詢的時候,如果沒有聲明需要刷新,並且緩存沒有超時的情況下,SqlSession都會取出當前緩存的數據,而不會再次發送SQL到資料庫。

每一次會話都對應自己的一級緩存,作用範圍比較小,一旦會話關閉就查詢不到了

1.2快速入門

需求:當第一次查詢id=1的Monster後,再次查詢id=1的monster對象,就會直接從一級緩存獲取,不會再次發出sql

(1)Monster實體類

package com.li.entity;

import java.util.Date;

/**
 * @author 李
 * @version 1.0
 */
public class Monster {
    //屬性和表的欄位對應
    private Integer id;
    private Integer age;
    private String name;
    private String email;
    private Date birthday;
    private double salary;
    private Integer gender;
    
    //省略全參、無參構造器、setter、getter、toString方法
}

(2)MonsterMapper介面方法

//查詢-根據id
public Monster getMonsterById(Integer id);
//查詢所有的Monster
public List<Monster> findAllMonster();

(3)映射文件(部分)

<mapper namespace="com.li.mapper.MonsterMapper">
    <!--配置getMonsterById方法-->
    <select id="getMonsterById" resultType="Monster">
        SELECT * FROM `monster` WHERE id=#{id};
    </select>

    <!--實現findAllMonster方法-->
    <select id="findAllMonster" resultType="Monster">
        SELECT * FROM `monster`;
    </select>
</mapper>

(4)測試(部分代碼)

//測試一級緩存
@Test
public void level1CacheTest() {
    System.out.println("==========第一次查詢=========");
    Monster monster = monsterMapper.getMonsterById(10);
    System.out.println("monster=" + monster);
    System.out.println("==========第二次查詢=========");
    Monster monster2 = monsterMapper.getMonsterById(10);
    System.out.println("monster=" + monster2);
    //關閉sqlSession會話
    if (sqlSession != null) {
        sqlSession.close();
    }
}

一級緩存預設打開,在同一個會話中,當重覆查詢時,不會再發出sql語句,而是從一級緩存中直接獲取數據:

image-20230302192738341

註意是重覆查詢,如果是不同的查詢操作還是會向資料庫發出sql

1.3一級緩存是什麼?

一級緩存到底是什麼?

我們通過查看SqlSession的結構可以看出,一級緩存就是一個HashMap,緩存其實就是一個本地存放的map對象,每一個SqlSession都會存放一個map對應的引用。

image-20230302211259587

1.4一級緩存的執行流程

MyBatis緩存機制

img

1.5一級緩存失效分析

1.5.1關閉SqlSession會話後,一級緩存失效

我們知道,一級緩存是和SqlSession會話關聯的,一旦SqlSession關閉了,一級緩存就會失效。測試如下:

//測試一級緩存失效
@Test
public void level1CacheTest2() {
    System.out.println("==========第1次查詢=========");
    Monster monster = monsterMapper.getMonsterById(10);
    System.out.println("monster=" + monster);
    //關閉sqlSession,一級緩存失效
    if (sqlSession != null) {
        sqlSession.close();
    }

    System.out.println("==========第2次查詢=========");
    sqlSession = MybatisUtils.getSqlSession();//重新獲取SqlSession對象
    monsterMapper = sqlSession.getMapper(MonsterMapper.class);//重新初始化
    Monster monster2 = monsterMapper.getMonsterById(10);
    System.out.println("monster2=" + monster2);
    if (this.sqlSession != null) {
        this.sqlSession.close();
    }
}

結果:可以看到兩次查詢都發出了sql操作,說明如果SqlSession會話關閉了,第二次查詢依然回到資料庫查詢,一級緩存失效。

image-20230302205202985 image-20230302205226114

1.5.2手動清理緩存,一級緩存失效

當執行sqlSession.clearCache()時(手動清理緩存),一級緩存失效。

clearCache()方法底層執行如下:

image-20230302210336097

測試方法如下:

//測試一級緩存失效
@Test
public void level1CacheTest3() {
    System.out.println("==========第1次查詢=========");
    Monster monster = monsterMapper.getMonsterById(10);
    System.out.println("monster=" + monster);

    //手動清理緩存,也會導致一級緩存失效
    sqlSession.clearCache();

    System.out.println("==========第2次查詢=========");
    Monster monster2 = monsterMapper.getMonsterById(10);
    System.out.println("monster2=" + monster2);
    if (this.sqlSession != null) {
        this.sqlSession.close();
    }
}

測試結果如下,查詢操作相同,且在同一個SqlSession會話內,但底層仍然到資料庫執行了兩次相同操作,這說明當手動清理緩存後,一級緩存也會失效。

image-20230302210108149

1.5.3對查詢的數據,進行增刪改操作時,一級緩存失效

在兩次相同的查詢中間進行update操作,是否會對一級緩存產生影響?

//如果被查詢的數據進行了增刪改操作,會導致一級緩存數據失效
@Test
public void level1CacheTest4() {
    System.out.println("==========第1次查詢=========");
    Monster monster = monsterMapper.getMonsterById(10);
    System.out.println("monster=" + monster);

    //對要查詢的數據id=10進行update操作
    monster.setName("金蟬子");
    monsterMapper.updateMonster(monster);

    System.out.println("==========第2次查詢=========");
    Monster monster2 = monsterMapper.getMonsterById(10);
    System.out.println("monster2=" + monster2);
    if (sqlSession != null) {
        sqlSession.commit();//註意提交事務
        sqlSession.close();
    }
}

如下,在兩次相同查詢操作之間進行update操作,一級緩存同樣失效了,因為第二次查詢操作仍然向資料庫發出sql語句。

image-20230302213411173

2.二級緩存

2.1基本介紹

  1. 二級緩存和一級緩存都是為了提高檢索效率而創建的技術
  2. 兩者最大的區別就是作用域範圍不一樣
    • 一級緩存的作用域是sqlSession會話級別,在一次會話中有效
    • 二級緩存的作用域是全局範圍,針對不同的SqlSession會話都有效。二級緩存又稱"全局緩存",是基於namespace級別的緩存,一個namespace對應一個二級緩存
  3. 當一級緩存的會話被關閉時,一級緩存的數據就會被放入二級緩存,前提是二級緩存是開啟的。

二級緩存原理圖:

開啟二級緩存後,會使用CachingExecutor裝飾Executor,進入一級緩存的查詢流程前,先在CachingExecutor進行二級緩存的查詢,具體的工作流程如下所示。

二級緩存開啟後,同一個namespace下的所有操作語句,都影響著同一個Cache,即二級緩存被多個SqlSession共用,是一個全局的變數。當開啟緩存後,數據的查詢執行的流程就是 二級緩存 -> 一級緩存 -> 資料庫

2.2快速入門

(1)mybatis-config.xml配置中開啟二級緩存

設置名 描述 有效值 預設值
cacheEnabled 全局性開啟或關閉所有映射器配置文件中已配置的任何緩存 true、false true
<settings>
    <!--開啟二級緩存,預設下值為true-->
    <setting name="cacheEnabled" value="true"/>
</settings>

(2)使用二級緩存時entity類實現序列化介面(serializable),因為二級緩存可能使用到序列化技術

大部分情況下,二級緩存不去置序列化也可以使用,只是有些二級緩存產品可能用到序列化

image-20230303184936552

(3)在對應的xxMapper.xml中設置二級緩存的策略

<!--配置二級緩存
FIFO:先進先出,按對象進入緩存的順序來移除它們
flushInterval:刷新間隔為60000ms,即60s
size:存儲結果對象或列表的 512 個引用,預設為1024
readOnly:只讀屬性,如果只用於讀操作,建議設置成true,如果有修改操作,則設置為false(預設)
-->
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>

(4)測試

//測試二級緩存
@Test
public void level2CacheTest() {
    System.out.println("==========第一次查詢=========");
    Monster monster = monsterMapper.getMonsterById(5);
    System.out.println("monster=" + monster);
    //關閉這個會話
    if (sqlSession != null) {
        sqlSession.close();
    }

    System.out.println("==========第二次查詢=========");
    //獲取新的sqlSession會話
    sqlSession = MybatisUtils.getSqlSession();
    monsterMapper = sqlSession.getMapper(MonsterMapper.class);
    Monster monster2 = monsterMapper.getMonsterById(5);
    System.out.println("monster=" + monster2);
    if (this.sqlSession != null) {
        this.sqlSession.close();
    }
}

測試結果:二級緩存的作用域是全局範圍,因此不同的sqlSession會話都有效

二級緩存命中率 = 緩存生效的次數 / 總查詢的次數

image-20230303192148902 image-20230303192202032

2.3註意事項和使用細節

2.3.1二級緩存的策略的參數

要啟用全局的二級緩存,只需要在你的 SQL 映射文件中添加一行:

<cache/>

可以通過 cache 元素的屬性來修改你的策略。比如:

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

配置創建了一個 FIFO 緩存,每隔 60 秒刷新,最多可以存儲結果對象或列表的 512 個引用,而且返回的對象被認為是只讀的,因此對它們進行修改可能會在不同線程中的調用者產生衝突。

eviction:緩存的回收策略。

flushInterval(刷新間隔)屬性為任意的正整數,設置的值應該是一個以毫秒為單位時間。 預設情況是不設置,也就是沒有刷新間隔,緩存僅僅會在調用語句時刷新。

size(引用數目)屬性為任意正整數,欲緩存對象的大小和運行環境中可用的記憶體資源有關。預設值為 1024。

readOnly(只讀)屬性可以為 true 或 false。只讀緩存會給所有調用者返回緩存對象的相同實例。 因此這些對象不能被修改,從而使性能提升。而可讀寫的緩存會(通過序列化)返回緩存對象的拷貝。 速度上會慢一些,但是更安全,因此預設值是 false。

2.3.2四大策略

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

2.3.3如何禁用二級緩存

image-20230303201252854

(1)在mybatis-config.xml文件的settings標簽中設置二級緩存的開關。

註意這裡的配置只是和二級緩存有關,和一級緩存無關

<settings>
    <!--全局性開啟或關閉所有映射器配置文件中已經配置的任何緩存,可以理解為二級緩存的總開關,預設為true-->
    <setting name="cacheEnabled" value="false"/>
</settings>

(2)二級緩存的設置不僅要在配置文件中設置,還要在對應的映射文件中配置才有效。因此如果要禁用二級緩存,也可以在對應的映射文件中註銷cache元素,這時候二級緩存對該映射文件無效。

image-20230303200955511

(3)或者使用控制力度更加精確的方法,直接在配置方法上指定

設置useCache="false"可以禁用當前select語句的二級緩存,即每次查詢都會發出sql去查詢,預設情況為true

image-20230303200836507

註意:一般不用去修改,使用預設的即可

2.3.4刷新二級緩存的設置

insert,update,delete 操作數據後需要刷新緩存,如果不執行刷新緩存會出現臟讀:

image-20230303201525639

預設情況下 flushCache 的值為true,一般不用修改。

3.一級緩存和二級緩存的執行順序

緩存的執行順序為:二級緩存-->一級緩存-->資料庫

測試:驗證緩存的執行順序,我們事先打開二級緩存和一級緩存。

//二級緩存->一級緩存->資料庫
@Test
public void cacheSeqTest() {
    System.out.println("==========第1次查詢=========");
    //Cache Hit Ratio: 0.0
    Monster monster = monsterMapper.getMonsterById(8);
    System.out.println(monster);

    //當一級緩存的會話被關閉時,一級緩存的數據就會被放入二級緩存,前提是二級緩存是開啟的
    sqlSession.close();

    sqlSession = MybatisUtils.getSqlSession();
    monsterMapper = sqlSession.getMapper(MonsterMapper.class);
    System.out.println("==========第2次查詢=========");
    //從二級緩存獲取 id=8 的 monster信息 
    //Cache Hit Ratio: 0.5
    Monster monster2 = monsterMapper.getMonsterById(8);
    System.out.println(monster2);

    System.out.println("==========第3次查詢=========");
    //這時一二級緩存都有數據,但是由於先查詢二級緩存,因此數據依然是從二級緩存中獲取的
    //Cache Hit Ratio: 0.6666666666666666
    Monster monster3 = monsterMapper.getMonsterById(8);
    System.out.println(monster3);
    sqlSession.close();
}
image-20230303203436307

註意事項:

不會出現一級緩存和二級緩存中有同一個數據,因為二級緩存的數據是在一級緩存關閉之後才有的。(當一級緩存的會話被關閉時,如果二級緩存開啟了,一級緩存的數據就會被放入二級緩存)

//分析執行順序,二級緩存的數據是在一級緩存被關閉之後才有的,不會出現一二級緩存同時擁有相同數據的情況
@Test
public void cacheSeqTest2() {
    System.out.println("==========第1次查詢=========");
    //二級緩存命中率 Cache Hit Ratio: 0.0,走資料庫
    Monster monster = monsterMapper.getMonsterById(8);
    System.out.println(monster);

    System.out.println("==========第2次查詢=========");
    //Cache Hit Ratio: 0.0
    //拿的是一級緩存的數據,不會發出sql
    Monster monster2 = monsterMapper.getMonsterById(8);
    System.out.println(monster2);

    System.out.println("==========第3次查詢=========");
    //Cache Hit Ratio: 0.0
    //拿的是一級緩存的數據,不會發出sql
    Monster monster3 = monsterMapper.getMonsterById(8);
    System.out.println(monster3);
    if (sqlSession != null) {
        sqlSession.close();
    }
}

4.EhCache緩存

4.1基本介紹

Ehcache配置文件ehcache.xml

  1. EhCache是一個純Java的緩存框架,具有快速、精幹等特點
  2. Mybatis有自己預設的二級緩存(前面我們已經講過了),但是在實際項目中,往往使用的是更加專業的第三方緩存產品,作為MyBatis的二級緩存,EhCache就是非常優秀的緩存產品

4.2配置和使用EhCache

(1)加入相關依賴,修改pom.xml文件

image-20230303210842513
<dependencies>
    <!--引入EhCache核心庫-->
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache-core</artifactId>
        <version>2.6.11</version>
    </dependency>
    <!--引入需要使用的slf4j-->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.25</version>
    </dependency>
    <!--引入mybatis整合ehcache庫-->
    <dependency>
        <groupId>org.mybatis.caches</groupId>
        <artifactId>mybatis-ehcache</artifactId>
        <version>1.2.1</version>
    </dependency>
</dependencies>

(2)確保mybatis-config.xml文件打開了二級緩存

<settings>
    <!--不配置也可以,因為二級緩存預設是打開的-->
    <setting name="cacheEnabled" value="true"/>
</settings>

(3)在resource目錄下加入ehcache.xml 配置文件

Java Ehcache緩存的timeToIdleSeconds和timeToLiveSeconds區別 - TaoBye

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <!--diskStore:為緩存路徑,ehcache分為記憶體和磁碟兩級,此屬性定義磁碟的緩存位置。參數解釋如下:
       user.home – 用戶主目錄
       user.dir  – 用戶當前工作目錄
       java.io.tmpdir – 預設臨時文件路徑 -->
    <diskStore path="java.io.tmpdir/Tmp_EhCache"/>

    <!--defaultCache:預設緩存策略,當ehcache找不到定義的緩存時,使用這個緩存策略。只能定義一個-->
    <!--name:緩存名稱。
      maxElementsInMemory:緩存最大數目
      maxElementsOnDisk:硬碟最大緩存個數。
      eternal:對象是否永久有效,一但設置了,timeout將不起作用。
      overflowToDisk:是否保存到磁碟,當系統宕機時
      timeToIdleSeconds:設置對象在失效前的允許閑置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,預設值是0,也就是可閑置時間無窮大。
      timeToLiveSeconds:設置對象在失效前允許存活時間(單位:秒)。最大時間介於創建時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,預設是0,也就是對象存活時間無窮大。
      diskPersistent:是否緩存虛擬機重啟期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
      diskSpoolBufferSizeMB:這個參數設置DiskStore(磁碟緩存)的緩存區大小。預設是30MB。每個Cache都應該有自己的一個緩衝區。
      diskExpiryThreadIntervalSeconds:磁碟失效線程運行時間間隔,預設是120秒。
      memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理記憶體。預設策略是LRU(最近最少使用)。你可以設置為FIFO(先進先出)或是LFU(較少使用)。
      clearOnFlush:記憶體數量最大時是否清除。
      memoryStoreEvictionPolicy:可選策略有:LRU(最近最少使用,預設策略)、FIFO(先進先出)、LFU(最少訪問次數)。
      FIFO,first in first out,這個是大家最熟的,先進先出。
      LFU, Less Frequently Used,就是上面例子中使用的策略,直白一點就是講一直以來最少被使用的。如上面所講,緩存的元素有一個hit屬性,hit值最小的將會被清出緩存。
      LRU,Least Recently Used,最近最少使用的,緩存的元素有一個時間戳,當緩存容量滿了,而又需要騰出地方來緩存新的元素的時候,那麼現有緩存元素中時間戳離當前時間最遠的元素將被清出緩存。-->
    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>
</ehcache>

(4)在XxxMapper.xml中啟用了EhCace,當然原來Mybatis自帶的緩存配置需要註銷

<!--啟用ehcache-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

(5)測試

//測試二級緩存
@Test
public void ehCacheTest() {
    System.out.println("==========第1次查詢=========");
    Monster monster = monsterMapper.getMonsterById(5);
    System.out.println("monster=" + monster);

    //關閉當前會話,一級緩存數據失效,將數據放入二級緩存(此時為 ehcache)
    if (sqlSession != null) {
        sqlSession.close();
    }

    //獲取新的sqlSession會話
    sqlSession = MybatisUtils.getSqlSession();
    monsterMapper = sqlSession.getMapper(MonsterMapper.class);

    System.out.println("==========第2次查詢=========");
    //從二級緩存ehcache中獲取數據,不會發出sql
    Monster monster2 = monsterMapper.getMonsterById(5);
    System.out.println("monster=" + monster2);

    System.out.println("==========第3次查詢=========");
    //還是從二級緩存獲取數據,不會發出sql
    Monster monster3 = monsterMapper.getMonsterById(5);
    System.out.println("monster=" + monster3);
    if (this.sqlSession != null) {
        this.sqlSession.close();
    }
}
image-20230303214150372 image-20230303214215749

4.3EhCache緩存細節說明

如何理解EhCache和Mybatis緩存的關係?

  1. MyBatis提供了一個Cache介面,只要實現了該Cache介面,就可以作為二級緩存產品和MyBatis整合使用,EhCache就是實現了該介面。

  2. MyBatis預設情況(即一級緩存)是使用的PerpetualCache類實現Cache介面的,是核心類

    image-20230303215916202 image-20230303220130039

  3. 當我們使用了EhCache後,就是EhcacheCache類實現Cache介面,它是核心類

  4. 緩存的本質就是 Map<Object,Object>

    image-20230303220404464

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • html篇之《標簽分類和嵌套規則》 一、常用標簽 (1) <div></div> 一個區塊容器標記,可以包含圖片、表格、段落等各種html元素 (2) <span></span> 沒有實際意義,為了應用樣式 二、標簽分類 (1) 塊級標簽 獨占一行,會換行 包含: <div></div>、<ul>< ...
  • 訪問者模式是一種將演算法與對象結構分離的軟體設計模式。它可以讓你在不修改對象結構的情況下,對對象結構中的元素進行不同的操作。訪問者模式的優點是符合單一職責原則,優秀的擴展性和靈活性。缺點是具體元素對訪問者公佈細節,違反了迪米特原則,而且如果元素類經常變化,會導致訪問者類需要頻繁修改。 訪問者模式適合在 ...
  • 數據字典是系統中基本的必不可少的功能,在多種多樣的系統中,數據字典表的設計都大同小異。但是使用方式確是多種多樣,設計好一套易用的數據字典功能模塊,可以使開發事半功倍。 常用的數據字典使用方式: 直接在SQL語句中LEFT JOIN (當然是不推薦這樣用的) 查詢出原始數據,然後再根據原始數據需要的字 ...
  • Hello,Golang 一、開發環境搭建 1. 下載 SDK 1 // Go官網下載地址 2 https://golang.org/dl/ 3 ​ 4 // Go官方鏡像站(推薦) 5 https://golang.google.cn/dl/ 2. 安裝 由於Go語言是一門跨平臺的編譯型語言,我們 ...
  • 環境 odoo-14.0.post20221212.tar Web Controllers Controllers 控制器需要提供可擴展性,就像Model,但不能使用相同的機制,因為先決條件(已載入模塊的資料庫)可能還不可用(例如,未創建資料庫或未選擇資料庫)。 因此,控制器提供了自己的與模型的擴展 ...
  • 簡介 chatgpt-java是一個OpenAI的Java版SDK,支持開箱即用。目前以支持官網全部Api。支持最新版本GPT-3.5-Turbo模型以及whisper-1模型。增加chat聊天對話以及語音文件轉文字,語音翻譯。 開源地址:https://github.com/Grt1228/cha ...
  • 下載安裝包 Prometheus windows_exporter Grafana 下載地址:https://share.weiyun.com/D9sdiWoC 工作原理 Exporter 監控工具,獲取數據 Prometheus 普羅米修斯時序資料庫,用來存儲和查詢監控數據 Grafana 儀錶盤 ...
  • 哈嘍兄弟們,今天我們來試試,如何只用13行代碼,給抖音APP視頻自動點贊! 前因後果 事情是這樣的,昨晚表弟晚上一兩點了,房間燈還亮著,原來是還在用手機刷某音視頻,我搶過手機一看,好家伙,連刷十個都是美女,喜歡列表也全是MM。 我看他手動點贊手都點累了,乾脆熬個夜,給他寫一個自動點贊的代碼,今晚他就 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...