成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

使用 Spring Boot3.3 結合 Redisson RBloomFilter 有效應對緩存穿透問題

開發 前端
通過結合 Spring Boot3.3、Redisson 和 MyBatis-Plus,實現了使用 RBloomFilter 防止緩存穿透的商品查詢功能。本文提供了詳細的代碼示例,包括前后端的實現以及數據庫初始化步驟,展示了如何在實際項目中應用布隆過濾器來提高系統性能。

在電商平臺中,商品查詢是最頻繁的操作之一。隨著商品數量的增加和用戶訪問量的激增,系統可能面臨頻繁的緩存穿透問題。緩存穿透通常是由惡意請求或用戶錯誤輸入導致的:當請求的數據不存在時,查詢將直接落到數據庫上,無法通過緩存系統加速響應。這不僅增加了數據庫的負載,還可能導致系統崩潰。在這種情況下,布隆過濾器作為一種高效的概率型數據結構,可以通過快速判斷某個數據是否存在于集合中,來有效減少無效的數據庫查詢,從而解決緩存穿透問題。

布隆過濾器的基本原理是在初始化時,設置一個長度為 m 的位數組,并通過 k 個哈希函數將數據映射到位數組上。當有新元素加入時,布隆過濾器會將該元素的哈希值映射到數組的 k 個位置上,并將這些位置的位設置為 1。在查詢某個元素是否存在時,布隆過濾器會通過同樣的 k 個哈希函數檢查對應的位是否都為 1,如果有任意一位為 0,則說明該元素不存在;如果所有位都為 1,則說明該元素可能存在。

布隆過濾器的優勢在于它的空間和時間效率都非常高,適合處理大規模數據的快速查詢。然而,它的缺點是存在一定的誤判率,即可能會錯誤地判斷一個不存在的元素為存在。為了降低誤判率,布隆過濾器的設計需要合理選擇位數組的長度 m 和哈希函數的數量 k。

在電商平臺中,我們可以在緩存系統之前使用布隆過濾器,對查詢請求進行預篩選,以減少對數據庫的直接訪問。本文將通過 Spring Boot3.3 結合 Redisson 的 RBloomFilter 實現這一方案,并展示如何通過 MyBatis-Plus 實現商品數據的查詢,同時結合前端展示,完整演示該技術方案的實現細節。

運行效果:

有商品

圖片圖片

無商品

圖片圖片

若想獲取項目完整代碼以及其他文章的項目源碼,且在代碼編寫時遇到問題需要咨詢交流,歡迎加入下方的知識星球。

項目結構

  • Spring Boot 3.3
  • Redisson
  • Redis
  • MyBatis-Plus
  • Thymeleaf 模板引擎
  • Bootstrap + JS 前端框架

配置項目環境

Maven 配置 (pom.xml)

在 pom.xml 中引入必要的依賴:

<?xml versinotallow="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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.3.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.icoderoad</groupId>
	<artifactId>bloomfilter</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>bloomfilter</name>
	<description>BloomFilter Demo project for Spring Boot</description>
	
	<properties>
		<java.version>17</java.version>
		<bootstrap.version>5.3.0</bootstrap.version>
		<jquery.version>3.6.0</jquery.version>
		<mybatis-spring.version>3.0.3</mybatis-spring.version>
		<mybatis-plus-boot-starter.version>3.5.7</mybatis-plus-boot-starter.version>
		<redisson.version>3.35.0</redisson.version>
	</properties>
	<dependencies>
		
		<!-- Spring Boot Starter Web -->
	    <dependency>
	        <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-starter-web</artifactId>
	    </dependency>
	
	     <!-- MyBatis-Plus 依賴 -->
	    <dependency>
	        <groupId>com.baomidou</groupId>
	        <artifactId>mybatis-plus-boot-starter</artifactId>
	        <version>${mybatis-plus-boot-starter.version}</version>
	    </dependency>
	    
	     <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis-spring.version}</version>
      	</dependency>
	
	    <!-- MySQL 驅動 -->
	    <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
	
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

	    <!-- Redisson -->
	    <dependency>
	        <groupId>org.redisson</groupId>
   			<artifactId>redisson</artifactId>
	        <version>${redisson.version}</version>
	    </dependency>
	
	    <!-- Thymeleaf -->
	    <dependency>
	        <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-starter-thymeleaf</artifactId>
	    </dependency>
		 
	    <dependency>
	        <groupId>org.projectlombok</groupId>
	        <artifactId>lombok</artifactId>
	        <optional>true</optional>
	    </dependency>
	    
	    <!-- Bootstrap 和 JS -->
	    <dependency>
	        <groupId>org.webjars</groupId>
	        <artifactId>bootstrap</artifactId>
	        <version>${bootstrap.version}</version>
	    </dependency>
	    <dependency>
	        <groupId>org.webjars</groupId>
	        <artifactId>jquery</artifactId>
	        <version>${jquery.version}</version>
	    </dependency>
	    

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
Yaml 配置 (application.yml)

在 application.yml 中配置 Redis、Redisson 以及 MyBatis-Plus 的相關信息:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/sensitive?useSSL=false&serverTimeznotallow=UTC
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  data:
    redis:
      host: localhost
      port: 6379
      password: 123456
      timeout: 60000
      database: 0
      lettuce:
        pool:
          max-active: 8
          max-idle: 8
          min-idle: 0
          max-wait: -1ms
  thymeleaf:
    cache: false

server:
  port: 8080

商品表創建與數據插入

商品表 SQL DDL 語句

首先創建商品表 product,包含商品的基本信息:

CREATE TABLE product (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL,
    stock INT NOT NULL
);
插入商品數據的 SQL 語句

插入20條示例數據到 product 表中:

INSERT INTO product (name, description, price, stock) VALUES
('商品1', '這是商品1的描述', 99.99, 100),
('商品2', '這是商品2的描述', 199.99, 50),
('商品3', '這是商品3的描述', 299.99, 150),
('商品4', '這是商品4的描述', 399.99, 200),
('商品5', '這是商品5的描述', 499.99, 10),
('商品6', '這是商品6的描述', 599.99, 5),
('商品7', '這是商品7的描述', 699.99, 300),
('商品8', '這是商品8的描述', 799.99, 400),
('商品9', '這是商品9的描述', 899.99, 500),
('商品10', '這是商品10的描述', 999.99, 600),
('商品11', '這是商品11的描述', 1099.99, 700),
('商品12', '這是商品12的描述', 1199.99, 800),
('商品13', '這是商品13的描述', 1299.99, 900),
('商品14', '這是商品14的描述', 1399.99, 1000),
('商品15', '這是商品15的描述', 1499.99, 1100),
('商品16', '這是商品16的描述', 1599.99, 1200),
('商品17', '這是商品17的描述', 1699.99, 1300),
('商品18', '這是商品18的描述', 1799.99, 1400),
('商品19', '這是商品19的描述', 1899.99, 1500),
('商品20', '這是商品20的描述', 1999.99, 1600);

實現商品查詢功能

商品實體類 (Product)
package com.icoderoad.bloomfilter.entity;

import java.math.BigDecimal;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import lombok.Data;

@TableName("product")
@Data
public class Product {

    @TableId
    private Long id;
    private String name;
    private String description;
    private BigDecimal price;
    private Integer stock;

}
商品Mapper接口 (ProductMapper)
package com.icoderoad.bloomfilter.mapper;


import org.apache.ibatis.annotations.Mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.icoderoad.bloomfilter.entity.Product;

@Mapper
public interface ProductMapper extends BaseMapper<Product> {
}
商品服務接口 (ProductService)
package com.icoderoad.bloomfilter.service;


import com.baomidou.mybatisplus.extension.service.IService;
import com.icoderoad.bloomfilter.entity.Product;

public interface ProductService  extends IService<Product> {
   public Product getProductById(Long id);
}
商品服務實現類 (ProductServiceImpl)
package com.icoderoad.bloomfilter.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.icoderoad.bloomfilter.entity.Product;
import com.icoderoad.bloomfilter.mapper.ProductMapper;
import com.icoderoad.bloomfilter.service.BloomFilterService;
import com.icoderoad.bloomfilter.service.ProductService;

@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {

	 @Autowired
	    private ProductMapper productMapper;

	    @Autowired
	    private BloomFilterService bloomFilterService;

	    @Autowired
	    private RedisTemplate<String, Object> redisTemplate;

	    @Override
	    public Product getProductById(Long id) {
	        String productId = id.toString();

	        // 使用布隆過濾器判斷商品是否存在
	        if (!bloomFilterService.mightContain(productId)) {
	            return null;
	        }

	        // 從 Redis 緩存中獲取數據
	        Product product = (Product) redisTemplate.opsForValue().get(productId);
	        if (product == null) {
	            // 如果緩存中沒有,從數據庫查詢
	            product = productMapper.selectById(id);
	            if (product != null) {
	                // 將數據放入緩存,并添加到布隆過濾器中
	                redisTemplate.opsForValue().set(productId, product);
	                bloomFilterService.addProductToBloomFilter(id);
	            }
	        }
	        return product;
	    }
	    
}

初始化布隆過濾器

BloomFilterService 接口和實現類

首先,創建 BloomFilterService 接口及其實現類,用于封裝布隆過濾器的操作:

package com.icoderoad.bloomfilter.service;

public interface BloomFilterService {
	
	void addProductToBloomFilter(Long id);

	boolean mightContain(String id);
}

實現類:

package com.icoderoad.bloomfilter.service.impl;

import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.icoderoad.bloomfilter.service.BloomFilterService;

import jakarta.annotation.PostConstruct;

@Service
public class BloomFilterServiceImpl implements BloomFilterService {

    @Autowired
    private RedissonClient redissonClient;

    private RBloomFilter<String> bloomFilter;

    // 初始化布隆過濾器
    @PostConstruct
    public void init() {
    	if( redissonClient!=null ) {
	        this.bloomFilter = redissonClient.getBloomFilter("productBloomFilter");
	        // 初始化布隆過濾器的大小和誤判率
	        this.bloomFilter.tryInit(1000000L, 0.01);
    	}
    }

    @Override
    public void addProductToBloomFilter(Long id) {
        bloomFilter.add(id.toString());
    }

    @Override
    public boolean mightContain(String id) {
        return bloomFilter.contains(id);
    }
}

創建 RedissonConfig 配置類

屬性類 RedisProperties:

package com.icoderoad.bloomfilter.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import lombok.Data;

@Configuration
@ConfigurationProperties(prefix = "spring.data.redis")
@Data
public class RedisProperties {

    private String host;
    private int port;
    private String password;
    private int timeout;
    private int database;

}

創建 RedissonConfig 配置類,從 application.yml 中讀取 Redis 配置:

package com.icoderoad.bloomfilter.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedissonConfig {
	
	@Autowired
    private RedisProperties redisProperties;
	
	@Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
	
	
    @Bean("redissonClient")
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer()
              .setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort())
              .setPassword(redisProperties.getPassword())
              .setConnectionPoolSize(10)
              .setConnectionMinimumIdleSize(5)
              .setTimeout(redisProperties.getTimeout())
              .setDatabase(redisProperties.getDatabase());

        return Redisson.create(config);
    }

}

說明

  • @Value 注解用于從 application.yml 中讀取配置屬性。
  • setAddress 方法中使用 redisHost 和 redisPort 構建 Redis 地址。
  • 其他 Redis 配置如密碼、連接超時、數據庫索引等,也從配置文件中讀取。

在啟動時初始化 BloomFilter (ApplicationRunner)

然后,在項目啟動時將商品數據添加到 BloomFilter 中:

package com.icoderoad.bloomfilter.init;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import com.icoderoad.bloomfilter.entity.Product;
import com.icoderoad.bloomfilter.mapper.ProductMapper;
import com.icoderoad.bloomfilter.service.BloomFilterService;

@Component
public class BloomFilterInitializer {

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private BloomFilterService bloomFilterService;

    @Bean
    public ApplicationRunner initializeBloomFilter() {
        return args -> {
            // 從數據庫中獲取所有商品
            List<Product> products = productMapper.selectList(null);
            // 將每個商品的ID添加到布隆過濾器中
            for (Product product : products) {
                bloomFilterService.addProductToBloomFilter(product.getId());
            }
        };
    }
}

這個 ApplicationRunner 會在 Spring Boot 應用啟動時運行,遍歷數據庫中的所有商品,并將它們的 ID 添加到布隆過濾器中。這確保了在系統啟動時,布隆過濾器已經初始化,并且包含所有現有商品的數據。

前端展示

HTML 頁面 (Thymeleaf 模板)

使用 Thymeleaf 結合 Bootstrap 實現前端頁面,允許用戶輸入商品ID并查詢商品信息:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>商品查詢</title>
    <link rel="stylesheet" href="/webjars/bootstrap/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <h1>商品查詢</h1>
    <form id="searchForm" th:action="@{/product/search}" method="get">
        <div class="form-group">
            <label for="productId">商品ID:</label>
            <input type="text" class="form-control" id="productId" name="productId" required>
        </div>
        <button type="submit" class="btn btn-primary">查詢</button>
    </form>

    <div id="productResult" th:if="${product != null}">
        <h2>商品信息</h2>
        <p>ID: <span th:text="${product.id}"></span></p>
        <p>名稱: <span th:text="${product.name}"></span></p>
        <p>描述: <span th:text="${product.description}"></span></p>
        <p>價格: <span th:text="${product.price}"></span></p>
        <p>庫存: <span th:text="${product.stock}"></span></p>
    </div>
</div>
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/bootstrap/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Controller 實現
package com.icoderoad.bloomfilter.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.icoderoad.bloomfilter.entity.Product;
import com.icoderoad.bloomfilter.service.ProductService;

@Controller
public class ProductController {

    @Autowired
    private ProductService productService;
    
    @GetMapping("/")
    public String index(Model model) {
        return "index";
    }

    @GetMapping("/product/search")
    public String searchProduct(@RequestParam("productId") Long productId, Model model) {
        Product product = productService.getProductById(productId);
        model.addAttribute("product", product);
        return "index";
    }
}

結論

通過結合 Spring Boot3.3、Redisson 和 MyBatis-Plus,實現了使用 RBloomFilter 防止緩存穿透的商品查詢功能。本文提供了詳細的代碼示例,包括前后端的實現以及數據庫初始化步驟,展示了如何在實際項目中應用布隆過濾器來提高系統性能。

今天就講到這里,如果有問題需要咨詢,大家可以直接留言或掃下方二維碼來知識星球找我,我們會盡力為你解答。

責任編輯:武曉燕 來源: 碼猿技術專欄
相關推薦

2024-09-26 09:28:06

內存Spring

2025-02-20 08:21:36

2017-12-28 22:22:05

2024-09-02 08:12:32

Spring策略MyBatis

2025-04-17 03:33:00

SpringSQL動態查詢

2024-08-29 08:23:22

EasyOCRSpring文字識別

2009-03-09 11:01:34

2024-10-14 13:26:42

2015-12-28 10:48:44

RedisSpring緩存實例

2024-03-06 13:29:15

人工智能雙碳能源管理

2016-07-15 18:10:16

Intel數據中心數據中心管理器

2021-12-02 13:56:33

勒索軟件攻擊網絡安全

2024-12-09 13:50:24

2023-10-04 19:43:38

2024-08-27 09:28:39

2023-01-31 08:37:11

緩存穿透擊穿

2024-09-05 09:35:58

CGLIBSpring動態代理

2010-08-26 13:00:53

無線網絡

2016-10-08 16:57:25

OracleOracle EPMOracle EPM系

2021-10-21 09:56:18

人工智能金融行業勒索軟件
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美一区视频 | 国产成人精品午夜视频免费 | 亚洲一区二区三区免费视频 | 久久不射电影网 | 天天操精品视频 | 久久久久久久国产精品影院 | 日韩国产欧美视频 | 亚洲中字在线 | 亚洲伊人久久综合 | 狠狠躁天天躁夜夜躁婷婷老牛影视 | 夜夜艹| 久久精品国产亚洲夜色av网站 | 香蕉久久a毛片 | 国产亚洲网站 | 中文字幕第一页在线 | 久久国产一区 | 国产欧美日韩综合精品一 | 天天操天天干天天透 | 人成精品 | 国产欧美综合在线 | 一区二区av在线 | 一区二区三区四区视频 | 国产精品美女久久久久久免费 | 亚洲综合色网 | 欧美xxxx在线| 国产精品精品久久久 | 在线免费亚洲视频 | 亚洲激情网站 | 亚州av在线| 特一级黄色毛片 | 天天爱av| 一道本视频 | 韩日精品一区 | 国产精品178页 | 国产精品久久网 | 在线亚洲欧美 | 精品久久久久久 | www.888www看片 | 亚洲系列第一页 | 亚洲精品一区二区 | 亚洲国产精品一区二区久久 |