Spring Cache和EhCache實(shí)現(xiàn)緩存管理方式
1、認(rèn)識(shí) Spring Cache
Spring Cache是Spring提供的一整套緩存解決方案。它本身并不提供緩存實(shí)現(xiàn),而是提供統(tǒng)一的接口和代碼規(guī)范、配置、注解等,以便整合各種Cache方案,使用戶不用關(guān)心Cache的細(xì)節(jié)。
Spring支持“透明”地向應(yīng)用程序添加緩存,將緩存應(yīng)用于方法,在方法執(zhí)行前檢查緩存中是否有可用的數(shù)據(jù)。這樣可以減少方法執(zhí)行的次數(shù),同時(shí)提高響應(yīng)的速度。緩存的應(yīng)用方式“透明”,不會(huì)對(duì)調(diào)用者造成任何干擾。只要通過(guò)注解@EnableCaching啟用了緩存支持,Spring Boot就會(huì)自動(dòng)處理好緩存的基礎(chǔ)配置。
Spring Cache作用在方法上。當(dāng)調(diào)用一個(gè)緩存方法時(shí),會(huì)把該方法參數(shù)和返回結(jié)果作為一個(gè)“鍵值對(duì)”(key / value)存放在緩存中,下次用同樣的參數(shù)來(lái)調(diào)用該方法時(shí)將不再執(zhí)行該方法,而是直接從緩存中獲取結(jié)果進(jìn)行返回。所以在使用Spring Cache時(shí),要保證在緩存的方法和方法參數(shù)相同時(shí)返回相同的結(jié)果。
Spring Boot提供的聲明式緩存(cache)注解,如下表:
| 注解 | 說(shuō)明 |
|---|---|
| @EnableCaching | 開(kāi)啟緩存。 |
| @Cacheable | 可以作用在類和方法上,以鍵值對(duì)的方式緩存類或方法的返回值。 |
| @CachePut | 方法被調(diào)用,然后結(jié)果被緩存。 |
| @CacheEvict | 清空緩存。 |
| @Caching | 用來(lái)組合多個(gè)注解標(biāo)簽。 |
2、認(rèn)識(shí) EhCache
Spring Boot支持多種不同的緩存產(chǎn)品。在默認(rèn)情況下使用的是簡(jiǎn)單緩存,不建議在正式環(huán)境中使用。我們可以配置一些更加強(qiáng)大的緩存,比如Ehcache。
Ehcache是一種廣泛使用的開(kāi)源Java分布式緩存,它具有內(nèi)存和磁盤存儲(chǔ)、緩存加載器、緩存擴(kuò)展、緩存異常處理、GZIP緩存、Servlet 過(guò)濾器,以及支持 REST 和 SOAP API 等特點(diǎn)。
3、創(chuàng)建SpringBoot與MyBatis的整合項(xiàng)目
【實(shí)例】創(chuàng)建SpringBoot與MyBatis的整合項(xiàng)目,實(shí)現(xiàn)用戶信息的查詢、新增、修改、刪除功能。并使用 Spring Cache 和 EhCache 實(shí)現(xiàn)緩存管理,執(zhí)行結(jié)果如下圖:

3.1 創(chuàng)建數(shù)據(jù)表
在MySQL數(shù)據(jù)庫(kù)中創(chuàng)建用戶信息表(tb_user),并添加數(shù)據(jù)。
-- 判斷數(shù)據(jù)表是否存在,存在則刪除
DROP TABLE IF EXISTS tb_user;
-- 創(chuàng)建“用戶信息”數(shù)據(jù)表
CREATE TABLE IF NOT EXISTS tb_user
(
user_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用戶編號(hào)',
user_name VARCHAR(50) NOT NULL COMMENT '用戶姓名',
age INT DEFAULT(0) NOT NULL COMMENT '年齡',
blog_url VARCHAR(50) NOT NULL COMMENT '博客地址',
blog_remark VARCHAR(50) COMMENT '博客信息'
) COMMENT = '用戶信息表';
-- 添加數(shù)據(jù)
INSERT INTO tb_user(user_name,age,blog_url,blog_remark) VALUES('pan_junbiao的博客',32,'https://blog.csdn.net/pan_junbiao','您好,歡迎訪問(wèn) pan_junbiao的博客');
3.2 創(chuàng)建項(xiàng)目
(1)創(chuàng)建SpringBoot項(xiàng)目,項(xiàng)目結(jié)構(gòu)如下圖:

(2)添加pom.xml配置信息
在pom.xml配置文件中添加MyBatis、 MySQL的JDBC數(shù)據(jù)庫(kù)驅(qū)動(dòng)、Spring Boot 緩存支持啟動(dòng)器、Ehcache 緩存等。
<!-- MyBatis與SpringBoot整合依賴 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!-- MySQL的JDBC數(shù)據(jù)庫(kù)驅(qū)動(dòng) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<!-- 引入Thymeleaf模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Spring Boot緩存支持啟動(dòng)器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.3.2.RELEASE</version>
</dependency>
<!-- Ehcache緩存管理器 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
(3)配置相關(guān)信息
將默認(rèn)的application.properties文件的后綴修改為“.yml”,即配置文件名稱為:application.yml,并配置以下信息:
#Spring配置
spring:
#緩存管理器
cache:
type: ehcache
ehcache:
config: classpath:ehcache.xml #緩存加載配置文件
#使用Thymeleaf模板引擎
thymeleaf:
mode: HTML5
encoding: UTF-8
cache: false #使用Thymeleaf模板引擎,關(guān)閉緩存
servlet:
content-type: text/html
#DataSource數(shù)據(jù)源
datasource:
url: jdbc:mysql://localhost:3306/db_admin?useSSL=false&
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
#MyBatis配置
mybatis:
type-aliases-package: com.pjb.entity #別名定義
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #指定 MyBatis 所用日志的具體實(shí)現(xiàn),未指定時(shí)將自動(dòng)查找
map-underscore-to-camel-case: true #開(kāi)啟自動(dòng)駝峰命名規(guī)則(camel case)映射
lazy-loading-enabled: true #開(kāi)啟延時(shí)加載開(kāi)關(guān)
aggressive-lazy-loading: false #將積極加載改為消極加載(即按需加載),默認(rèn)值就是false
#lazy-load-trigger-methods: "" #阻擋不相干的操作觸發(fā),實(shí)現(xiàn)懶加載
cache-enabled: true #打開(kāi)全局緩存開(kāi)關(guān)(二級(jí)環(huán)境),默認(rèn)值就是true
4、配置EhCache緩存管理器
4.1 創(chuàng)建 ehcache.xml 配置文件
在 resources (資源目錄)下,創(chuàng)建 ehcache.xml 配置文件,配置信息如下:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 這個(gè)是磁盤存儲(chǔ)路徑,當(dāng)內(nèi)存緩存滿了的時(shí)候,就會(huì)往這里面放,
java.io.tmdir是操作系統(tǒng)緩存的臨時(shí)目錄,不同操作系統(tǒng)緩存目錄不一樣 -->
<diskStore path="java.io.tmpdir"/>
<!--defaultCache:echcache的默認(rèn)緩存策略 -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<cache name="userCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</cache>
</ehcache>
配置屬性說(shuō)明:
| 屬性 | 說(shuō)明 |
|---|---|
| <diskStore path="java.io.tmpdir"/> | 這個(gè)是磁盤存儲(chǔ)路徑,當(dāng)內(nèi)存緩存滿了的時(shí)候,就會(huì)往這里面放,java.io.tmdir是操作系統(tǒng)緩存的臨時(shí)目錄,不同操作系統(tǒng)緩存目錄不一樣。 |
| maxElementsInMemory | 內(nèi)存緩存中最多可以存放的元素?cái)?shù)量,若放入Cache中的元素超過(guò)這個(gè)數(shù)值,則有以下兩種情況: (1)若 overflowToDisk=true,則會(huì)將Cache中多出的元素放入磁盤文件中。 (2)若 overflowToDisk=false,則根據(jù)memoryStoreEvictionPolicy策略替換Cache中原有的元素。 |
| overflowToDisk | 內(nèi)存不足時(shí),是否啟用磁盤緩存。 |
| eternal | 緩存中對(duì)象是否永久有效。 |
| timeToIdleSeconds | 緩存數(shù)據(jù)在失效前的允許閑置時(shí)間(單位:秒),僅當(dāng) eternal=false 時(shí)使用,默認(rèn)值是0表示可閑置時(shí)間無(wú)窮大,若超過(guò)這個(gè)時(shí)間沒(méi)有訪問(wèn)此Cache中的某個(gè)元素,那么此元素將被從Cache中清除。 |
| timeToLiveSeconds | 緩存數(shù)據(jù)的總的存活時(shí)間(單位:秒),僅當(dāng) eternal=false 時(shí)使用,從創(chuàng)建開(kāi)始計(jì)時(shí),失效結(jié)束。 |
| maxElementsOnDisk | 磁盤緩存中最多可以存放的元素?cái)?shù)量,0表示無(wú)窮大。 |
| diskExpiryThreadIntervalSeconds | 磁盤緩存的清理線程運(yùn)行間隔,默認(rèn)是120秒。 |
| memoryStoreEvictionPolicy | 內(nèi)存存儲(chǔ)與釋放策略,即達(dá)到 maxElementsInMemory 限制時(shí),Ehcache會(huì)根據(jù)指定策略清理內(nèi)存,共有三種策略,分別為L(zhǎng)RU(最近最少使用)、LFU(最常用的)、FIFO(先進(jìn)先出)。 |
| defaultCache | 默認(rèn)緩存方式。 |
| cache | 自定義的緩存方式,自行設(shè)置 name。 |
4.2 配置緩存管理器
在 application.yml 配置文件中配置目標(biāo)緩存管理器,支持 Ehcache、Generic、Redis、Jcache等。這里配置使用Ehcache。
#Spring配置
spring:
#緩存管理器
cache:
type: ehcache
ehcache:
config: classpath:ehcache.xml #緩存加載配置文件
4.3 開(kāi)啟緩存功能
在SpringBoot項(xiàng)目啟動(dòng)入口類中添加注解@EnableCaching,開(kāi)啟緩存功能。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class SpringcacheDemoApplication
{
public static void main(String[] args)
{
SpringApplication.run(SpringcacheDemoApplication.class, args);
}
}
5、使用EhCache實(shí)現(xiàn)緩存管理
5.1 創(chuàng)建實(shí)體類(Entity層)
在com.pjb.entity包中,創(chuàng)建UserInfo類(用戶信息實(shí)體類)。
package com.pjb.entity;
import java.io.Serializable;
/**
* 用戶信息實(shí)體類
* @author pan_junbiao
**/
public class UserInfo implements Serializable
{
private int userId; //用戶編號(hào)
private String userName; //用戶姓名
private int age; //年齡
private String blogUrl; //博客地址
private String blogRemark; //博客信息
//省略getter與setter方法...
}
注意:實(shí)體類必須實(shí)現(xiàn) Serializable 接口,否則無(wú)法實(shí)現(xiàn)緩存功能。
5.2 數(shù)據(jù)庫(kù)映射層(Mapper層)
在com.pjb.mapper包中,創(chuàng)建UserMapper接口(用戶信息Mapper動(dòng)態(tài)代理接口)。
package com.pjb.mapper;
import com.pjb.entity.UserInfo;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
/**
* 用戶信息Mapper動(dòng)態(tài)代理接口
* @author pan_junbiao
**/
@Mapper
@Repository
public interface UserMapper
{
/**
* 根據(jù)用戶ID,獲取用戶信息
*/
@Select("SELECT * FROM tb_user WHERE user_id = #{userId}")
public UserInfo getUserById(int userId);
/**
* 新增用戶,并獲取自增主鍵
*/
@Insert("INSERT INTO tb_user(user_name,age,blog_url,blog_remark) VALUES(#{userName},#{age},#{blogUrl},#{blogRemark});")
@Options(useGeneratedKeys = true, keyColumn = "user_id", keyProperty = "userId")
public int insertUser(UserInfo userInfo);
/**
* 修改用戶
*/
@Update("UPDATE tb_user SET user_name = #{userName} ,age = #{age} ,blog_url = #{blogUrl} ,blog_remark = #{blogRemark} WHERE user_id = #{userId}")
public int updateUser(UserInfo userInfo);
/**
* 刪除用戶
*/
@Delete("DELETE FROM tb_user WHERE user_id = #{userId}")
public int deleteUser(int userId);
}
5.3 業(yè)務(wù)邏輯層(Service層)
在com.pjb.service包下,創(chuàng)建UserService接口(用戶信息業(yè)務(wù)邏輯接口)。
package com.pjb.service;
import com.pjb.entity.UserInfo;
/**
* 用戶信息業(yè)務(wù)邏輯接口
* @author pan_junbiao
**/
public interface UserService
{
/**
* 根據(jù)用戶ID,獲取用戶信息
*/
public UserInfo getUserById(int userId);
/**
* 新增用戶,并獲取自增主鍵
*/
public UserInfo insertUser(UserInfo userInfo);
/**
* 修改用戶
*/
public UserInfo updateUser(UserInfo userInfo);
/**
* 刪除用戶
*/
public int deleteUser(int userId);
}
在com.pjb.service.impl包下,創(chuàng)建UserServiceImpl類(用戶信息業(yè)務(wù)邏輯類)。
package com.pjb.service.impl;
import com.pjb.entity.UserInfo;
import com.pjb.mapper.UserMapper;
import com.pjb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
/**
* 用戶信息業(yè)務(wù)邏輯類
* @author pan_junbiao
**/
//注意:必須對(duì)應(yīng)配置文件ehcache.xml中cache節(jié)點(diǎn)的name屬性值
//@CacheConfig(cacheNames = "userCache")
@Service
public class UserServiceImpl implements UserService
{
@Autowired
private UserMapper userMapper;
//注意:必須對(duì)應(yīng)配置文件ehcache.xml中cache節(jié)點(diǎn)的name屬性值
private static final String CACHE_NAME = "userCache";
/**
* 根據(jù)用戶ID,獲取用戶信息
*/
@Override
@Cacheable(value = CACHE_NAME, key = "#userId")
public UserInfo getUserById(int userId)
{
return userMapper.getUserById(userId);
}
/**
* 新增用戶,并獲取自增主鍵
*/
@Override
@CachePut(value = CACHE_NAME, key = "#userInfo.userId")
public UserInfo insertUser(UserInfo userInfo)
{
userMapper.insertUser(userInfo);
return userInfo;
}
/**
* 修改用戶
*/
@Override
@CachePut(value = CACHE_NAME, key = "#userInfo.userId")
public UserInfo updateUser(UserInfo userInfo)
{
userMapper.updateUser(userInfo);
return userInfo;
}
/**
* 刪除用戶
*/
@Override
@CacheEvict(value = CACHE_NAME, key = "#userId")
public int deleteUser(int userId)
{
return userMapper.deleteUser(userId);
}
}
從上述代碼可以看出,查詢用戶的方法使用了 @Cacheable 注解來(lái)開(kāi)啟緩存。添加和修改方法使用了 @CachePut 注解,它是先處理方法,然后把結(jié)果進(jìn)行緩存的。要想刪除數(shù)據(jù),則需要使用 @CacheEvict 注解來(lái)清空緩存。
@CacheConfig注解:如果所有的 @Cacheable() 里面都有一個(gè) value=“xxx” 的屬性,這顯然如果方法多了,寫起來(lái)也是挺累的,如果可以一次性聲明完 那就省事了,所以有了 @CacheConfig 這個(gè)配置,@CacheConfig is a class-level annotation that allows to share the cache names,如果你在方法寫別的名字,那么依然以方法的名字為準(zhǔn)。
5.4 控制器方法(Controller層)
在com.pjb.controller包中,創(chuàng)建UserController類(用戶控制器),實(shí)現(xiàn)用戶數(shù)據(jù)的查詢、新增、修改、刪除,并實(shí)現(xiàn)數(shù)據(jù)的返回。
package com.pjb.controller;
import com.pjb.entity.UserInfo;
import com.pjb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
/**
* 用戶信息控制器
* @author pan_junbiao
**/
@Controller
@RequestMapping("/user")
public class UserController
{
@Autowired
private UserService userService;
/**
* 獲取用戶信息
*/
@RequestMapping("getUserById")
public ModelAndView getUserById(int userId)
{
//根據(jù)用戶ID,獲取用戶信息
UserInfo userInfo = userService.getUserById(userId);
if(userInfo==null)
{
userInfo = new UserInfo();
}
//返回結(jié)果
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("userInfo",userInfo);
modelAndView.setViewName("/user-info.html");
return modelAndView;
}
/**
* 新增用戶
*/
@ResponseBody
@RequestMapping("insertUser")
public boolean insertUser()
{
//創(chuàng)建新用戶
UserInfo userInfo = new UserInfo();
userInfo.setUserName("pan_junbiao的博客");
userInfo.setAge(32);
userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");
userInfo.setBlogRemark("您好,歡迎訪問(wèn) pan_junbiao的博客");
//執(zhí)行新增方法
userService.insertUser(userInfo);
//返回結(jié)果
return userInfo.getUserId() > 0 ? true : false;
}
/**
* 修改用戶
*/
@ResponseBody
@RequestMapping("updateUser")
public boolean updateUser(int userId)
{
UserInfo userInfo = new UserInfo();
userInfo.setUserId(userId);
userInfo.setUserName("pan_junbiao的博客_02");
userInfo.setAge(35);
userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");
userInfo.setBlogRemark("您好,歡迎訪問(wèn) pan_junbiao的博客");
//執(zhí)行修改方法
userService.updateUser(userInfo);
//返回結(jié)果
return true;
}
/**
* 刪除用戶
*/
@ResponseBody
@RequestMapping("deleteUser")
public boolean deleteUser(int userId)
{
//執(zhí)行新增方法
int result = userService.deleteUser(userId);
//返回結(jié)果
return result > 0 ? true : false;
}
}
5.5 顯示頁(yè)面(View層)
在 resources/templates 目錄下,創(chuàng)建 user-info.html 用戶信息顯示頁(yè)面。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>用戶信息</title>
<meta name="author" content="pan_junbiao的博客">
<style>
table { border-collapse: collapse; margin-bottom: 10px}
table,table tr th, table tr td { border:1px solid #000000; padding: 5px 10px;}
</style>
</head>
<body>
<div align="center">
<table>
<caption>用戶信息</caption>
<tr>
<th>用戶ID:</th>
<td th:text="${userInfo.userId}"></td>
</tr>
<tr>
<th>用戶名稱:</th>
<td th:text="${userInfo.userName}"></td>
</tr>
<tr>
<th>年齡:</th>
<td th:text="${userInfo.age}"></td>
</tr>
<tr>
<th>博客地址:</th>
<td th:text="${userInfo.blogUrl}"></td>
</tr>
<tr>
<th>備注信息:</th>
<td th:text="${userInfo.blogRemark}"></td>
</tr>
</table>
</div>
</body>
</html>
至此,項(xiàng)目已經(jīng)編寫完成,執(zhí)行結(jié)果如下圖:

接著運(yùn)行項(xiàng)目的其他方法,然后多次訪問(wèn)查詢方法的URL,體驗(yàn)緩存效果。主要觀察數(shù)據(jù)庫(kù)是否進(jìn)行了操作,如果數(shù)據(jù)庫(kù)沒(méi)有操作數(shù)據(jù)而正常返回?cái)?shù)據(jù),則代表緩存成功。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
mybatis數(shù)組和集合的長(zhǎng)度判斷及插入方式
這篇文章主要介紹了mybatis數(shù)組和集合的長(zhǎng)度判斷及插入方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
mybatis-plus報(bào)錯(cuò)Not Found TableInfoCache異常問(wèn)題
在集成百度uid-generator過(guò)程中,MyBatis-Plus報(bào)錯(cuò)NotFoundTableInfoCache異常,解決方法:檢查實(shí)體類是否繼承了官方model,確保實(shí)體類對(duì)應(yīng)的mapper已正確注入,在使用@Component注解時(shí),應(yīng)保證相關(guān)依賴已注入2024-09-09
spring?cache注解@Cacheable緩存穿透詳解
這篇文章主要介紹了spring?cache注解@Cacheable緩存穿透詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Java數(shù)據(jù)庫(kù)連接池之c3p0簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了Java數(shù)據(jù)庫(kù)連接池之c3p0簡(jiǎn)介的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
JavaEE實(shí)現(xiàn)前后臺(tái)交互的文件上傳與下載
這篇文章主要介紹了JavaEE實(shí)現(xiàn)前后臺(tái)交互的文件上傳與下載,分享相關(guān)技術(shù),實(shí)現(xiàn)文件上傳下載功能,需要的朋友可以參考下2015-11-11
Java如何避免死鎖和競(jìng)態(tài)條件的實(shí)現(xiàn)
本文主要介紹了Java如何避免死鎖和競(jìng)態(tài)條件的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
Java數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)之循環(huán)鏈表
循環(huán)鏈表是另一種形式的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)。它的特點(diǎn)是表中最后一個(gè)結(jié)點(diǎn)的指針域指向頭結(jié)點(diǎn),整個(gè)鏈表形成一個(gè)環(huán)。本文將為大家詳細(xì)介紹一下循環(huán)鏈表的特點(diǎn)與使用,需要的可以了解一下2021-12-12

