2024-08-29

Spring Boot 3 和 JDK 17 的组合尚未广泛可用,因为 Spring Boot 3 是基于 Java 17 的发布候选版本。Spring Boot 2.5.x 是最后支持 Java 8 的 Spring Boot 版本。

考虑到这一点,我将提供一个示例配置,展示如何在 Spring Boot 2.5.x(最接近 Spring Boot 3 的稳定版本)中使用 Shiro 和 JWT 以及 Redis。




@Configuration
public class ShiroConfig {
 
    @Bean
    public Realm realm() {
        // 配置 Realm 用于身份验证
        return new MyRealm();
    }
 
    @Bean
    public DefaultWebSecurityManager securityManager(Realm realm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
        return securityManager;
    }
 
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 配置 Shiro Filter 规则
        return shiroFilterFactoryBean;
    }
}
 
public class MyRealm extends AuthorizingRealm {
 
    @Autowired
    private UserService userService;
 
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        // 实现认证逻辑
    }
 
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 实现授权逻辑
    }
}
 
@Configuration
public class JwtConfig {
 
    @Value("${jwt.secret}")
    private String secret;
 
    @Bean
    public JWTTokenFilter jwtTokenFilter() {
        return new JWTTokenFilter();
    }
 
    // 其他 JWT 配置 Bean
}
 
public class JWTTokenFilter extends AuthenticatingFilter {
 
    @Override
    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        // 实现 JWT 登录尝试检测逻辑
    }
 
    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        // 实现创建 JWT Token 逻辑
    }
 
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        // 实现访问拒绝时的逻辑
    }
}
 
@Configuration
public class RedisConfig {
 
    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        return new LettuceConne
2024-08-29

问题1:浅谈集群版Redis和Gossip协议

Redis Cluster使用Gossip协议来维护集群的状态,包括节点的元数据信息。Gossip协议主要用于节点间的信息交换和状态更新。

Gossip协议的工作机制:

  1. 节点随机选择部分其他节点发送数据。
  2. 被选择的节点会重复此过程,消息会在网络中随机扩散。
  3. 节点接收到消息后,更新本地状态,然后继续以一定概率传播消息。

问题2:mybatis底层原理

MyBatis 是一个优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 解决了 SQL 和 Java 之间的映射问题。

MyBatis 的主要组件包括:

  1. SqlSessionFactory:用于创建 SqlSession,类似于 JDBC 中的 Connection。
  2. SqlSession:是 MyBatis 的核心接口,用于执行命令,获取映射器和管理事务。
  3. Mapper:是 MyBatis 的映射器接口,用于定义 SQL 映射语句。
  4. SQL Mappings:是 MyBatis 的映射语句,包括 <select>, <insert>, <update>, <delete> 等标签。

MyBatis 的工作流程:

  1. 配置 MyBatis 配置文件,包括数据库连接信息、事务管理和映射文件。
  2. 通过 SqlSessionFactoryBuilder 创建 SqlSessionFactory。
  3. 通过 SqlSessionFactory 创建 SqlSession。
  4. 通过 SqlSession 获取映射器接口实例。
  5. 通过映射器接口执行 SQL 映射语句。
  6. 事务提交或回滚。

问题3:面试中的展示

面试中,你可以通过以下方式来展示你对MyBatis底层原理的理解:

  1. 提供MyBatis配置文件的简化版本,并解释其主要组件。
  2. 描述MyBatis如何处理SQL映射语句,包括解析、编译和执行。
  3. 展示如何使用MyBatis进行CRUD操作,并解释每个步骤的作用。
  4. 说明MyBatis的事务管理和缓存机制,以及它们如何工作。

记得,展示你的知识应该是自信和流畅的,避免语言混乱和错误。

2024-08-29

由于Redis 6.2.6是一个较新版本,并且Linux下的安装方法可能会随着版本更新而变化,因此,以下是一个通用的安装步骤:

  1. 更新系统包信息:



sudo apt-get update
  1. 安装必要的依赖项:



sudo apt-get install build-essential tcl
  1. 下载Redis 6.2.6源代码:



wget http://download.redis.io/releases/redis-6.2.6.tar.gz
  1. 解压源代码:



tar xzf redis-6.2.6.tar.gz
  1. 编译Redis:



cd redis-6.2.6
make
  1. 运行测试:



make test
  1. 安装Redis:



sudo make install
  1. 配置Redis:

    可以复制Redis的示例配置文件到/etc/redis/并编辑它:




sudo cp redis.conf /etc/redis/redis.conf
sudo nano /etc/redis/redis.conf
  1. 启动Redis服务器:



redis-server /etc/redis/redis.conf
  1. 检查Redis服务器状态:



redis-cli ping

如果返回PONG,则表示Redis已成功安装并运行。

注意:以上步骤可能根据你的Linux发行版(如Debian、Ubuntu、CentOS等)和已安装的软件包版本略有不同。如果你使用的是CentOS或者Red Hat,你可能需要使用yumdnf代替apt-get。如果你需要将Redis作为服务运行,你可能还需要创建一个systemd服务文件。

2024-08-29

Redis 的官方 Windows 版本可能不是最新的,因为官方的 Redis 项目主要关注于 Linux 和 macOS 系统。要在 Windows 上安装最新版本的 Redis,你可以使用微软维护的 Windows 版本,或者使用 WSL(Windows Subsystem for Linux)来运行最新的 Linux 发行版,其中包括最新版本的 Redis。

以下是在 Windows 上安装 Redis 的步骤:

  1. 使用 WSL 安装最新版本的 Redis:

    • 启用 WSL 2 特性(需要 Windows 18917 或更高版本的更新)。
    • 安装适用于 Linux 的 Windows 子系统。
    • 安装一个 Linux 发行版(如 Ubuntu)。
    • 在 Linux 子系统中安装 Redis:

      
      
      
      sudo apt update
      sudo apt install redis-server
    • 启动 Redis 服务:

      
      
      
      redis-server
  2. 使用微软提供的 Redis 版本:

    • 访问微软的 GitHub 仓库:https://github.com/MicrosoftArchive/redis
    • 下载最新版本的 Redis 安装包。
    • 解压并运行安装程序。
    • 安装完成后,你可以通过 Windows 服务面板启动 Redis 服务器。

请注意,由于 Redis 主要在 Linux 和 macOS 上进行开发和测试,微软维护的 Windows 版本可能不如官方版本稳定和安全,而且可能不支持最新的 Redis 特性。如果你需要最新的 Redis 特性和稳定性,使用 WSL 是更好的选择。

2024-08-29

RediSearch 是一个为 Redis 设计的全文搜索引擎,它可以针对存储在 Redis 中的数据提供实时的、可靠的全文搜索服务。

以下是一个使用 RediSearch 的 Python 示例:

首先,确保你已经安装了 redisearchredis 包。




pip install redisearch redis

然后,你可以使用以下代码来使用 RediSearch:




from redisearch import Client, TextField, NumericField
from redisearch.aggregate import AggregateRequest, Aggregate
 
# 连接到 Redis
client = Client('my_index')
 
# 创建一个文本字段和一个数值字段
text = TextField('body')
num = NumericField('price')
 
# 创建索引
client.create_index((text, num))
 
# 添加文档到索引
client.add_document('doc1', title = 'Hello world', body = 'This is a sample document', price = 100)
client.add_document('doc2', title = 'Another doc', body = 'This is another sample document', price = 200)
 
# 执行搜索
res = client.search('body:sample')
 
# 打印搜索结果
for doc in res.docs:
    print(doc.id, doc.title, doc.body, doc.price)
 
# 使用聚合功能
agg_req = AggregateRequest('@price:sum')
res = client.aggregate(agg_req)
 
# 打印聚合结果
for row in res.rows:
    print(row)

这个示例展示了如何创建一个索引、添加文档、执行搜索和使用聚合功能。在实际应用中,你需要根据你的具体需求来调整字段定义和查询参数。

2024-08-29

在不同的操作系统上,Redis的安装和启动方法可能会有所不同。以下是在Linux系统上安装和启动Redis的基本步骤:

  1. 使用包管理器安装Redis:



sudo apt-get update
sudo apt-get install redis-server
  1. 启动Redis服务:



sudo systemctl start redis-server
  1. 确认Redis正在运行:



redis-cli ping

如果返回PONG,则表示Redis服务器正在运行。

  1. (可选)配置Redis:

    如果需要自定义Redis配置,可以编辑 /etc/redis/redis.conf 文件,然后重启Redis服务:




sudo systemctl restart redis-server

以上步骤适用于基于Debian的系统,如Ubuntu。对于基于RPM的系统,如CentOS,你可能需要使用 yumdnf 替换 apt-get

如果你想从源代码安装或者使用最新版本的Redis,你可以从Redis官网(https://redis.io/)下载源代码,编译安装:




# 下载源代码
wget http://download.redis.io/releases/redis-6.2.6.tar.gz
# 解压
tar xzf redis-6.2.6.tar.gz
# 进入目录
cd redis-6.2.6
# 编译
make
# 安装
sudo make install

安装完成后,你可以通过指定安装目录下的 redis-server 启动Redis:




# 启动Redis服务器
redis-server

启动Redis客户端与上述命令类似,你可以使用安装目录下的 redis-cli 工具:




# 连接到本地Redis服务器
redis-cli

以上步骤提供了基本的Redis安装和启动方法,你可以根据自己的需求进行相应的调整。

2024-08-29



local redis_host = "127.0.0.1"
local redis_port = 6379
local redis_password = "your_redis_password"
 
local function connect_to_redis()
    local redis = require "resty.redis"
    local red = redis:new()
    red:set_timeout(1000) -- 1 秒超时
 
    -- 连接到 Redis 服务器
    local ok, err = red:connect(redis_host, redis_port)
    if not ok then
        ngx.say("连接到 Redis 失败: ", err)
        return
    end
 
    -- 如果设置了密码,则进行认证
    if redis_password and redis_password ~= "" then
        ok, err = red:auth(redis_password)
        if not ok then
            ngx.say("Redis 认证失败: ", err)
            return
        end
    end
 
    return red
end
 
-- 使用 Redis 连接池
local function fetch_from_redis(red, key)
    local res, err = red:get(key)
    if not res then
        ngx.say("查询 Redis 失败: ", err)
        return
    end
    if res == ngx.null then
        res = nil
    end
    return res
end
 
-- 将数据写入 Redis
local function save_to_redis(red, key, value)
    local ok, err = red:set(key, value)
    if not ok then
        ngx.say("写入 Redis 失败: ", err)
        return
    end
    return true
end
 
-- 示例:使用 Redis
local red = connect_to_redis()
if not red then
    ngx.say("无法建立 Redis 连接")
    return
end
 
-- 获取数据
local value = fetch_from_redis(red, "my_key")
if value then
    ngx.say("获取的值: ", value)
else
    ngx.say("键不存在")
end
 
-- 保存数据
local is_saved = save_to_redis(red, "my_key", "my_value")
if is_saved then
    ngx.say("数据保存成功")
else
    ngx.say("数据保存失败")
end
 
-- 关闭 Redis 连接
red:close()

这段代码展示了如何在OpenResty环境中使用Lua脚本连接Redis,获取数据,保存数据,并处理可能出现的错误。这是一个简化的例子,实际应用中可能需要更复杂的错误处理和资源管理。

2024-08-29



#include "adlist.h"
#include "dict.h"
#include "redis.h"
#include "server.h"
 
/* 示例函数:解释Redis的过期策略和内存淘汰策略 */
void explainExpireAndEvictionPolicies(void) {
    printf("\n");
    printf("## Redis过期策略\n");
    printf("Redis使用两种策略来管理过期的键:惰性检查和定时任务。\n");
    printf("1. 惰性检查:当一个键被访问时,会检查它是否过期。\n");
    printf("2. 定时任务:每秒钟运行10次,随机抽查一些键,删除其中已经过期的键。\n");
 
    printf("\n");
    printf("## Redis内存淘汰策略\n");
    printf("当Redis的内存超出限制时,会根据配置的淘汰策略来移除键:\n");
    printf("- noeviction: 不进行任何淘汰,当内存不足时,新写入命令会报错。\n");
    printf("- allkeys-lru: 当内存不足以容纳更多数据时,使用最近最少使用算法来淘汰键。\n");
    printf("- allkeys-random: 随机淘汰键。\n");
    printf("- volatile-lru: 只对设置了过期时间的键进行最近最少使用算法的淘汰。\n");
    printf("- volatile-random: 随机淘汰设置了过期时间的键。\n");
    printf("- volatile-ttl: 淘汰即将过期的键,优先淘汰TTL最短的键。\n");
}
 
/* 示例函数:模拟Redis配置内存淘汰策略 */
void simulateRedisConfigSetEvictionPolicy(int policy) {
    switch(policy) {
        case REDIS_MAXMEMORY_NO_EVICTION:
            printf("设置内存淘汰策略为:noeviction\n");
            break;
        case REDIS_MAXMEMORY_ALLKEYS_LRU:
            printf("设置内存淘汰策略为:allkeys-lru\n");
            break;
        case REDIS_MAXMEMORY_ALLKEYS_RANDOM:
            printf("设置内存淘汰策略为:allkeys-random\n");
            break;
        case REDIS_MAXMEMORY_VOLATILE_LRU:
            printf("设置内存淘汰策略为:volatile-lru\n");
            break;
        case REDIS_MAXMEMORY_VOLATILE_RANDOM:
            printf("设置内存淘汰策略为:volatile-random\n");
            break;
        case REDIS_MAXMEMORY_VOLATILE_TTL:
            printf("设置内存淘汰策略为:volatile-ttl\n");
            break;
        default:
            printf("未知的淘汰策略:%d\n", policy);
            break;
    }
}
 
/* 示例函数:模拟Redis根据策略淘汰键 */
void simulateRedisEvictKeys(void) {
    printf("\n");
    printf("## 淘汰键\n");
    printf("当达到内存限制时,Redis会根据配置的策略选择一些键进行淘汰。\n");
    printf("这里模拟淘汰键的过程...\n");
}
 
/* 示例函数:模拟Redis的内存淘汰过程 */
void simulateRedisEvictionProcess(void) {
    printf("\n");
    printf("## 模拟内存淘汰过程\n");
    printf("Redis会定期检查内存使用情况,并根据配置的淘汰策略来释放内存。\n");
2024-08-29

缓存穿透:查询不存在的数据,缓存和数据库都不会命中,导致请求直接打到数据库。

解决方法

  1. 使用布隆过滤器:在缓存之前加一层布隆过滤器,可以高效地判断一个元素是否可能存在于集合中。
  2. 缓存空对象:查询不存在的数据时,也将空对象存入缓存,并设置一个较短的过期时间。

缓存击穿:缓存失效时,大量请求直接打到数据库。

解决方法

  1. 设置热点数据永不过期或过期时间长一些。
  2. 使用分布式锁:更新缓存的时候获取分布式锁,保证同时只有一个线程去数据库查询最新数据并更新缓存。

缓存雪崩:缓存集体失效,大量请求打到数据库。

解决方法

  1. 设置缓存数据的随机过期时间,避免集体失效。
  2. 实现服务降级策略,在缓存失效时,通过限流或者熔断等手段避免大量请求打到数据库。
  3. 提前监控缓存的健康状况,在发现大量缓存失效前手动刷新缓存。
2024-08-29

在Windows系统中卸载Redis,你可以按照以下步骤操作:

  1. 停止Redis服务:

    打开命令提示符(以管理员身份),输入以下命令停止Redis服务:

    
    
    
    sc stop Redis
  2. 删除Redis服务:

    输入以下命令从系统中删除Redis服务:

    
    
    
    sc delete Redis
  3. 删除Redis可执行文件:

    找到Redis安装目录,通常在 C:\Program Files\Redis,将整个Redis文件夹删除。

  4. 删除Redis配置文件(可选):

    如果你在安装Redis时创建了配置文件,并且它被放置在了如 C:\ProgramData\Redis 等目录中,你可以手动删除这个目录。

请注意,如果Redis是通过其他方式安装的,比如使用Windows服务或者第三方管理工具,卸载过程可能会有所不同。如果你使用的是Windows服务来管理Redis,你可能需要使用服务管理工具来停止和删除服务。如果你使用的是某个Redis管理工具,可能需要通过该工具提供的界面来进行卸载。