<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>一个欲儿的博客</title><link>https://www.anyuer.club/</link><description>一个欲儿的博客</description><item><title>Spring Security + Redis 的无状态分布式认证架构设计</title><link>https://www.anyuer.club/?id=294</link><description>&lt;h1&gt;传统Session和JWT的弊端&lt;/h1&gt;&lt;h2&gt;Session&lt;br/&gt;&lt;/h2&gt;&lt;p&gt;在传统Web开发中，服务器通过Tomcat的 HttpSession（基于Cookie中的 JSESSIONID）维持状态。但在现代微服务与前后端分离架构下，这种方案存在天然弊端：&lt;/p&gt;&lt;p&gt;1.集群横向扩展困难：Session常驻单机内存，多台服务器间同步成本极高。&lt;/p&gt;&lt;p&gt;2.安全缺陷：基于Cookie的认证天然难以防范CSRF（跨站请求伪造）攻击。&lt;/p&gt;&lt;p&gt;3.为了解决有状态（Stateful）的痛点，业界普遍转向无状态（Stateless）架构。&lt;/p&gt;&lt;h2&gt;JWT&lt;br/&gt;&lt;/h2&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/06/202606051780672062316915.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;JWT仅适用于单向、短期、无状态的边缘授权（如文件下载凭证、邮件激活码）；而对于需要强管控、高并发、支持滑动续期和踢人下线的企业级核心用户系统，Redis Token 才是生产环境的终极解法。&lt;/p&gt;&lt;h1&gt;实现思路&lt;/h1&gt;&lt;p&gt;1.请求进入网关或Tomcat后，自定义过滤器 RedisTokenFilter 拦截请求，解析 HTTP Header 中的 Authorization 字段。&lt;/p&gt;&lt;p&gt;2.过滤器拿着Token去Redis集群检索。若命中，则说明该用户处于合法登录状态。随后将其包装为框架可识别的令牌，注入 SecurityContextHolder（底层基于 ThreadLocal，确保多线程并发下的线程隔离与安全）。&lt;/p&gt;&lt;p&gt;3.请求流向Spring Security的核心鉴权层（AuthorizationFilter）。鉴权层根据 SecurityConfig 中配置的黑白名单规则，比对当前线程上下文中是否存在令牌。核验通过则放行至 Controller，否则直接响应 403。&lt;/p&gt;&lt;h1&gt;代码实现&lt;/h1&gt;&lt;h2&gt;SQL数据表&lt;br/&gt;&lt;/h2&gt;&lt;p&gt;如果你还想做权限管理，我建议把数据库的用户表，增加一个字段用来区分权限。&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;--&amp;nbsp;phpMyAdmin&amp;nbsp;SQL&amp;nbsp;Dump
--&amp;nbsp;version&amp;nbsp;5.2.3
--&amp;nbsp;主机：&amp;nbsp;localhost
--&amp;nbsp;服务器版本：&amp;nbsp;5.7.44-log
--&amp;nbsp;PHP&amp;nbsp;版本：&amp;nbsp;8.2.28

SET&amp;nbsp;SQL_MODE&amp;nbsp;=&amp;nbsp;&amp;quot;NO_AUTO_VALUE_ON_ZERO&amp;quot;;
START&amp;nbsp;TRANSACTION;
SET&amp;nbsp;time_zone&amp;nbsp;=&amp;nbsp;&amp;quot;+00:00&amp;quot;;


/*!40101&amp;nbsp;SET&amp;nbsp;@OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT&amp;nbsp;*/;
/*!40101&amp;nbsp;SET&amp;nbsp;@OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS&amp;nbsp;*/;
/*!40101&amp;nbsp;SET&amp;nbsp;@OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION&amp;nbsp;*/;
/*!40101&amp;nbsp;SET&amp;nbsp;NAMES&amp;nbsp;utf8mb4&amp;nbsp;*/;

--
--&amp;nbsp;数据库：&amp;nbsp;`auth_study`
--

--&amp;nbsp;--------------------------------------------------------

--
--&amp;nbsp;表的结构&amp;nbsp;`s_users`
--

CREATE&amp;nbsp;TABLE&amp;nbsp;`s_users`&amp;nbsp;(
&amp;nbsp;&amp;nbsp;`uid`&amp;nbsp;int(11)&amp;nbsp;NOT&amp;nbsp;NULL,
&amp;nbsp;&amp;nbsp;`role`&amp;nbsp;varchar(11)&amp;nbsp;NOT&amp;nbsp;NULL
)&amp;nbsp;ENGINE=InnoDB&amp;nbsp;DEFAULT&amp;nbsp;CHARSET=utf8mb4;

--
--&amp;nbsp;转存表中的数据&amp;nbsp;`s_users`
--

INSERT&amp;nbsp;INTO&amp;nbsp;`s_users`&amp;nbsp;(`uid`,&amp;nbsp;`role`)&amp;nbsp;VALUES
(1,&amp;nbsp;&amp;#39;user&amp;#39;),
(2,&amp;nbsp;&amp;#39;admin&amp;#39;);

--
--&amp;nbsp;转储表的索引
--

--
--&amp;nbsp;表的索引&amp;nbsp;`s_users`
--
ALTER&amp;nbsp;TABLE&amp;nbsp;`s_users`
&amp;nbsp;&amp;nbsp;ADD&amp;nbsp;PRIMARY&amp;nbsp;KEY&amp;nbsp;(`uid`);
COMMIT;

/*!40101&amp;nbsp;SET&amp;nbsp;CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT&amp;nbsp;*/;
/*!40101&amp;nbsp;SET&amp;nbsp;CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS&amp;nbsp;*/;
/*!40101&amp;nbsp;SET&amp;nbsp;COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION&amp;nbsp;*/;&lt;/pre&gt;&lt;h2&gt;SecurityConfig&lt;/h2&gt;&lt;p&gt;可以看到，login接口是所有人哪怕未登录的游客也可以访问，但是admin接口是必须要权限为admin的用户才可以访问，hello接口的话登录了都可以访问&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;package&amp;nbsp;com.redisauth.config;

import&amp;nbsp;com.redisauth.util.RedisUtils;
import&amp;nbsp;org.springframework.context.annotation.Bean;
import&amp;nbsp;org.springframework.context.annotation.Configuration;
import&amp;nbsp;org.springframework.security.config.annotation.web.builders.HttpSecurity;
import&amp;nbsp;org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import&amp;nbsp;org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import&amp;nbsp;org.springframework.security.config.http.SessionCreationPolicy;
import&amp;nbsp;org.springframework.security.web.SecurityFilterChain;
import&amp;nbsp;org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public&amp;nbsp;class&amp;nbsp;SecurityConfig&amp;nbsp;{

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;final&amp;nbsp;RedisUtils&amp;nbsp;redisUtils;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;SecurityConfig(RedisUtils&amp;nbsp;redisUtils)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.redisUtils&amp;nbsp;=&amp;nbsp;redisUtils;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Bean
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;SecurityFilterChain&amp;nbsp;securityFilterChain(HttpSecurity&amp;nbsp;http)&amp;nbsp;throws&amp;nbsp;Exception&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;http
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.csrf(AbstractHttpConfigurer::disable)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.formLogin(AbstractHttpConfigurer::disable)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.httpBasic(AbstractHttpConfigurer::disable)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.addFilterBefore(new&amp;nbsp;AuthorityFilter(redisUtils),&amp;nbsp;UsernamePasswordAuthenticationFilter.class)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.sessionManagement(session&amp;nbsp;-&amp;gt;&amp;nbsp;session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.authorizeHttpRequests(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;auth&amp;nbsp;-&amp;gt;&amp;nbsp;auth
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.requestMatchers(&amp;quot;/login&amp;quot;).permitAll()&amp;nbsp;//&amp;nbsp;允许未登录时访问登录接口
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.requestMatchers(&amp;quot;/admin&amp;quot;).hasRole(&amp;quot;admin&amp;quot;)&amp;nbsp;//&amp;nbsp;允许用户权限为admin的用户登录
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.anyRequest().authenticated()&amp;nbsp;//&amp;nbsp;其它所有剩余接口默认都需要登录
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;http.build();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;AuthorityFilter&lt;br/&gt;&lt;/h2&gt;&lt;p&gt;当客户端携带该Token请求受保护的业务接口时，请求首先被AuthorityFilter安全过滤器拦截，过滤器从请求头提取出Token并拼接成对应的TokenKey去Redis中检索JSON字符串，若未命中则直接放行，由后续的Spring Security鉴权拦截器因上下文为空而统一响应403拒绝访问。
如果成功获取到JSON字符串，过滤器会将其反序列化解析出用户ID和角色，随后为了防御僵尸Token偷跑，过滤器利用解析出的用户ID实时去Redis中读取最新的UidKey，并将当前请求携带的Token与Redis中记录的最新活跃Token进行字符串一致性比对。
若比对完全一致，证明当前请求来自最后登录的合法设备，过滤器便为该角色组装框架认账的权限列表并注入当前请求的线程上下文中恢复合法身份，同时同步为当前的TokenKey和UidKey执行expire操作完成生命周期对齐的滑动续期；反之若比对不一致，说明该Token已被新设备顶替，过滤器则直接拒绝恢复其身份并顺手将该残余的TokenKey从Redis中连根拔除以释放内存，最后调用过滤链放行方法将请求安全传递给后续的路由鉴权关卡。&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;package&amp;nbsp;com.redisauth.config;

import&amp;nbsp;com.fasterxml.jackson.databind.JsonNode;
import&amp;nbsp;com.fasterxml.jackson.databind.ObjectMapper;
import&amp;nbsp;com.redisauth.util.RedisUtils;
import&amp;nbsp;jakarta.servlet.FilterChain;
import&amp;nbsp;jakarta.servlet.ServletException;
import&amp;nbsp;jakarta.servlet.http.HttpServletRequest;
import&amp;nbsp;jakarta.servlet.http.HttpServletResponse;
import&amp;nbsp;org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import&amp;nbsp;org.springframework.security.core.GrantedAuthority;
import&amp;nbsp;org.springframework.security.core.authority.SimpleGrantedAuthority;
import&amp;nbsp;org.springframework.security.core.context.SecurityContextHolder;
import&amp;nbsp;org.springframework.util.StringUtils;
import&amp;nbsp;org.springframework.web.filter.OncePerRequestFilter;

import&amp;nbsp;java.io.IOException;
import&amp;nbsp;java.util.ArrayList;
import&amp;nbsp;java.util.List;
import&amp;nbsp;java.util.concurrent.TimeUnit;

public&amp;nbsp;class&amp;nbsp;AuthorityFilter&amp;nbsp;extends&amp;nbsp;OncePerRequestFilter&amp;nbsp;{

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;final&amp;nbsp;RedisUtils&amp;nbsp;redisUtils;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;final&amp;nbsp;ObjectMapper&amp;nbsp;objectMapper&amp;nbsp;=&amp;nbsp;new&amp;nbsp;ObjectMapper();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;AuthorityFilter(RedisUtils&amp;nbsp;redisUtils)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.redisUtils&amp;nbsp;=&amp;nbsp;redisUtils;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected&amp;nbsp;void&amp;nbsp;doFilterInternal(HttpServletRequest&amp;nbsp;request,&amp;nbsp;HttpServletResponse&amp;nbsp;response,&amp;nbsp;FilterChain&amp;nbsp;filterChain)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throws&amp;nbsp;ServletException,&amp;nbsp;IOException&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;token&amp;nbsp;=&amp;nbsp;request.getHeader(redisUtils.HEADER);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(StringUtils.hasText(token))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;redisKey&amp;nbsp;=&amp;nbsp;redisUtils.tokenPreKey&amp;nbsp;+&amp;nbsp;token;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;jsonStr&amp;nbsp;=&amp;nbsp;redisUtils.get(redisKey);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(StringUtils.hasText(jsonStr))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;1.&amp;nbsp;解析&amp;nbsp;JSON&amp;nbsp;数据
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;JsonNode&amp;nbsp;jsonNode&amp;nbsp;=&amp;nbsp;objectMapper.readTree(jsonStr);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;uid&amp;nbsp;=&amp;nbsp;jsonNode.get(&amp;quot;uid&amp;quot;).asText();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;role&amp;nbsp;=&amp;nbsp;jsonNode.get(&amp;quot;role&amp;quot;).asText();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;=====&amp;nbsp;漏掉的单端核心校验开始&amp;nbsp;=====
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;uidKey&amp;nbsp;=&amp;nbsp;redisUtils.uidPreKey&amp;nbsp;+&amp;nbsp;uid;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;currentActiveToken&amp;nbsp;=&amp;nbsp;redisUtils.get(uidKey);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(token.equals(currentActiveToken))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;只有携带的&amp;nbsp;Token&amp;nbsp;确实是当前&amp;nbsp;Redis&amp;nbsp;记录的最活跃&amp;nbsp;Token&amp;nbsp;时，才放行并续期
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;List&amp;lt;GrantedAuthority&amp;gt;&amp;nbsp;authorities&amp;nbsp;=&amp;nbsp;new&amp;nbsp;ArrayList&amp;lt;&amp;gt;();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;authorities.add(new&amp;nbsp;SimpleGrantedAuthority(&amp;quot;ROLE_&amp;quot;&amp;nbsp;+&amp;nbsp;role));

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UsernamePasswordAuthenticationToken&amp;nbsp;authentication&amp;nbsp;=
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;UsernamePasswordAuthenticationToken(uid,&amp;nbsp;null,&amp;nbsp;authorities);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SecurityContextHolder.getContext().setAuthentication(authentication);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;同步双向续期
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redisUtils.expire(redisKey,&amp;nbsp;30,&amp;nbsp;TimeUnit.MINUTES);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redisUtils.expire(uidKey,&amp;nbsp;30,&amp;nbsp;TimeUnit.MINUTES);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;else&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;旧设备，直接从&amp;nbsp;Redis&amp;nbsp;删除
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redisUtils.delete(redisKey);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;=====&amp;nbsp;单端核心校验结束&amp;nbsp;=====
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;catch&amp;nbsp;(Exception&amp;nbsp;e)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.logger.error(&amp;quot;解析用户安全上下文失败&amp;quot;,&amp;nbsp;e);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;filterChain.doFilter(request,&amp;nbsp;response);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;TestController&lt;/h2&gt;&lt;p&gt;当用户调用登录接口并传入用户ID时，系统首先通过Mapper映射器校验该用户在数据库中是否存在，若不存在则直接返回错误提示阻断流程。
校验通过后，系统利用定义在工具类中的统一前缀配合用户ID拼接出唯一的UidKey，并立即去Redis中检索该键对应的值，若能获取到说明该账号此前已在其他设备登录。
此时系统会严格遵循先清道后建新凭证的顺序，立刻调用删除命令将该旧Token作为键的TokenKey从Redis内存中彻底抹除，以此确保旧设备的身份凭证死透，从根本上解决高并发下的数据覆盖Bug。
清除完旧通道后，系统利用UUID生成一个全新的Token串并组装出对应的新TokenKey，同时将最新的用户ID和角色信息格式化为JSON字符串，随后执行双向绑定写入，即把JSON字符串存入新TokenKey，把新Token串反向覆盖写入UidKey，并为这两个键设置完全一致的三十分钟逻辑过期时间，最后将新Token返回给前端。&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;package&amp;nbsp;com.redisauth.controller;


import&amp;nbsp;com.redisauth.entity.SUsers;
import&amp;nbsp;com.redisauth.mapper.SUsersMapper;
import&amp;nbsp;com.redisauth.util.RedisUtils;
import&amp;nbsp;org.springframework.beans.factory.annotation.Autowired;
import&amp;nbsp;org.springframework.util.StringUtils;
import&amp;nbsp;org.springframework.web.bind.annotation.GetMapping;
import&amp;nbsp;org.springframework.web.bind.annotation.PostMapping;
import&amp;nbsp;org.springframework.web.bind.annotation.RequestParam;
import&amp;nbsp;org.springframework.web.bind.annotation.RestController;

import&amp;nbsp;java.util.UUID;
import&amp;nbsp;java.util.concurrent.TimeUnit;

@RestController
public&amp;nbsp;class&amp;nbsp;TestController&amp;nbsp;{

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Autowired
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;SUsersMapper&amp;nbsp;sUsersMapper;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Autowired
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;RedisUtils&amp;nbsp;redisUtils;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PostMapping(&amp;quot;/login&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;String&amp;nbsp;login(@RequestParam(&amp;quot;uid&amp;quot;)&amp;nbsp;int&amp;nbsp;uid)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SUsers&amp;nbsp;sUsers&amp;nbsp;=&amp;nbsp;sUsersMapper.selectByPrimaryKey(uid);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(sUsers&amp;nbsp;==&amp;nbsp;null)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;quot;login&amp;nbsp;failed&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;uidKey&amp;nbsp;=&amp;nbsp;redisUtils.uidPreKey&amp;nbsp;+&amp;nbsp;sUsers.getUid();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;1.&amp;nbsp;严格先行：先检查并干掉旧设备，确保当前&amp;nbsp;Uid&amp;nbsp;相关的旧通道被完全清理
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;oldToken&amp;nbsp;=&amp;nbsp;redisUtils.get(uidKey);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(StringUtils.hasText(oldToken))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redisUtils.delete(redisUtils.tokenPreKey&amp;nbsp;+&amp;nbsp;oldToken);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;2.&amp;nbsp;后行：旧设备死透了，再开始为新设备张罗新凭证
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;newToken&amp;nbsp;=&amp;nbsp;UUID.randomUUID().toString();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;tokenKey&amp;nbsp;=&amp;nbsp;redisUtils.tokenPreKey&amp;nbsp;+&amp;nbsp;newToken;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;jsonValue&amp;nbsp;=&amp;nbsp;String.format(&amp;quot;{\&amp;quot;uid\&amp;quot;:%d,\&amp;quot;role\&amp;quot;:\&amp;quot;%s\&amp;quot;}&amp;quot;,&amp;nbsp;sUsers.getUid(),&amp;nbsp;sUsers.getRole());

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;3.&amp;nbsp;双向绑定写入&amp;nbsp;Redis
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redisUtils.set(tokenKey,&amp;nbsp;jsonValue,&amp;nbsp;30,&amp;nbsp;TimeUnit.MINUTES);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redisUtils.set(uidKey,&amp;nbsp;newToken,&amp;nbsp;30,&amp;nbsp;TimeUnit.MINUTES);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;newToken;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@GetMapping(&amp;quot;/hello&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;String&amp;nbsp;hello()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;quot;hello&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@GetMapping(&amp;quot;admin&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;String&amp;nbsp;admin()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;quot;admin&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}


}&lt;/pre&gt;&lt;h2&gt;RedisUtils&lt;br/&gt;&lt;/h2&gt;&lt;p&gt;redis相关做了封装，方便一点&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;package&amp;nbsp;com.redisauth.util;

import&amp;nbsp;org.springframework.data.redis.core.StringRedisTemplate;
import&amp;nbsp;org.springframework.stereotype.Component;

import&amp;nbsp;java.util.concurrent.TimeUnit;

/**
&amp;nbsp;*&amp;nbsp;Redis&amp;nbsp;基础操作通用工具类（基于&amp;nbsp;StringRedisTemplate）
&amp;nbsp;*/
@Component
public&amp;nbsp;class&amp;nbsp;RedisUtils&amp;nbsp;{

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;final&amp;nbsp;StringRedisTemplate&amp;nbsp;redisTemplate;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;String&amp;nbsp;HEADER&amp;nbsp;=&amp;nbsp;&amp;quot;Authorization&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;String&amp;nbsp;uidPreKey&amp;nbsp;=&amp;nbsp;&amp;quot;RedisAuth:uid:&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;String&amp;nbsp;tokenPreKey&amp;nbsp;=&amp;nbsp;&amp;quot;RedisAuth:token:&amp;quot;;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;RedisUtils(StringRedisTemplate&amp;nbsp;redisTemplate)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.redisTemplate&amp;nbsp;=&amp;nbsp;redisTemplate;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/**
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;写入缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*/
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;set(String&amp;nbsp;key,&amp;nbsp;String&amp;nbsp;value)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redisTemplate.opsForValue().set(key,&amp;nbsp;value);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/**
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;写入缓存并设置过期时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*/
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;set(String&amp;nbsp;key,&amp;nbsp;String&amp;nbsp;value,&amp;nbsp;long&amp;nbsp;timeout,&amp;nbsp;TimeUnit&amp;nbsp;unit)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redisTemplate.opsForValue().set(key,&amp;nbsp;value,&amp;nbsp;timeout,&amp;nbsp;unit);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/**
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;读取缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*/
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;String&amp;nbsp;get(String&amp;nbsp;key)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;redisTemplate.opsForValue().get(key);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/**
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;读取&amp;nbsp;Hash&amp;nbsp;指定字段值
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*/
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;String&amp;nbsp;hGet(String&amp;nbsp;key,&amp;nbsp;String&amp;nbsp;field)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Object&amp;nbsp;value&amp;nbsp;=&amp;nbsp;redisTemplate.opsForHash().get(key,&amp;nbsp;field);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;value&amp;nbsp;!=&amp;nbsp;null&amp;nbsp;?&amp;nbsp;value.toString()&amp;nbsp;:&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/**
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;删除&amp;nbsp;Key
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*/
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;Boolean&amp;nbsp;delete(String&amp;nbsp;key)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;redisTemplate.delete(key);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/**
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;设置/更新&amp;nbsp;Key&amp;nbsp;过期时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*/
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;Boolean&amp;nbsp;expire(String&amp;nbsp;key,&amp;nbsp;long&amp;nbsp;timeout,&amp;nbsp;TimeUnit&amp;nbsp;unit)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;redisTemplate.expire(key,&amp;nbsp;timeout,&amp;nbsp;unit);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/**
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;检查&amp;nbsp;Key&amp;nbsp;是否存在
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*/
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;Boolean&amp;nbsp;hasKey(String&amp;nbsp;key)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;redisTemplate.hasKey(key);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;主程序入口&lt;br/&gt;&lt;/h2&gt;&lt;p&gt;目的是关闭spring security自带的登录，以及mapper扫描&lt;br/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;package&amp;nbsp;com.redisauth;

import&amp;nbsp;org.mybatis.spring.annotation.MapperScan;
import&amp;nbsp;org.springframework.boot.SpringApplication;
import&amp;nbsp;org.springframework.boot.autoconfigure.SpringBootApplication;
import&amp;nbsp;org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;

@SpringBootApplication(exclude&amp;nbsp;=&amp;nbsp;{UserDetailsServiceAutoConfiguration.class})
@MapperScan(&amp;quot;com.redisauth.mapper&amp;quot;)
public&amp;nbsp;class&amp;nbsp;RedisAuthApplication&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;static&amp;nbsp;void&amp;nbsp;main(String[]&amp;nbsp;args)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SpringApplication.run(RedisAuthApplication.class,&amp;nbsp;args);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

}&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Fri, 05 Jun 2026 22:59:33 +0800</pubDate></item><item><title>LSPosed和LSPatch插件开发教程</title><link>https://www.anyuer.club/?id=293</link><description>&lt;h1&gt;简介&lt;/h1&gt;&lt;p&gt;其实他们都是基于xposed出现的框架，只是扩展了两个而已，所以他们的编程体系相同，但是LSPatch相比于LSPosed可以不需要root，但是其功能肯定不如LSPosed全面，同时呢，两个框架的运行模式也有不同&lt;/p&gt;&lt;h1&gt;LSPosed教程&lt;/h1&gt;&lt;h2&gt;创建项目&lt;br/&gt;&lt;/h2&gt;&lt;p&gt;打开Android studio&lt;/p&gt;&lt;p&gt;点New Project&amp;nbsp;&lt;/p&gt;&lt;p&gt;点Empty Views Activity&lt;/p&gt;&lt;p&gt;编程语言选java&amp;nbsp;&lt;/p&gt;&lt;p&gt;构建选build.gradle&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/06/202606031780499993725179.png&quot; alt=&quot;image.png&quot; width=&quot;561&quot; height=&quot;403&quot; border=&quot;0&quot; vspace=&quot;0&quot; title=&quot;image.png&quot; style=&quot;width: 561px; height: 403px;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;插件模块配置&lt;/h2&gt;&lt;p&gt;打开AndroidManifest.xml添加如下配置&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!--&amp;nbsp;是否为Xposed模块&amp;nbsp;--&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;meta-data
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;android:name=&amp;quot;xposedmodule&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;android:value=&amp;quot;true&amp;quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!--&amp;nbsp;模块的简介（在框架中显示）&amp;nbsp;--&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;meta-data
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;android:name=&amp;quot;xposeddescription&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;android:value=&amp;quot;我是Xposed模块简介&amp;quot;&amp;nbsp;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!--&amp;nbsp;模块最低支持的Api版本&amp;nbsp;一般填54即可&amp;nbsp;--&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;meta-data&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;android:name=&amp;quot;xposedminversion&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;android:value=&amp;quot;54&amp;quot;/&amp;gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/06/202606031780500429511652.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;另外提一嘴没有用的&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;android:icon=&amp;quot;@drawable/icon&amp;quot;&amp;nbsp;//换图标
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;android:label=&amp;quot;@string/app_name&amp;quot;&amp;nbsp;//换名字
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;android:roundIcon=&amp;quot;@drawable/icon&amp;quot;&amp;nbsp;//换图标&lt;/pre&gt;&lt;h2&gt;添加仓库配置&lt;/h2&gt;&lt;p&gt;打开setting.gradle添加&lt;br/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;maven&amp;nbsp;{&amp;nbsp;url=uri(&amp;quot;https://api.xposed.info&amp;quot;)&amp;nbsp;}&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/06/202606031780500549769578.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;h2&gt;导入jar包&lt;/h2&gt;&lt;p&gt;打开app module的build.gradle 添加&lt;br/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;compileOnly&amp;nbsp;&amp;#39;de.robv.android.xposed:api:82&amp;#39;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/06/202606031780500812187513.png&quot; alt=&quot;image.png&quot; width=&quot;729&quot; height=&quot;411&quot; border=&quot;0&quot; vspace=&quot;0&quot; title=&quot;image.png&quot; style=&quot;width: 729px; height: 411px;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;创建xposed_init&lt;/h2&gt;&lt;p&gt;将左上角选择为project，右键main，选择新建一个Directory，然后选择assets&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/06/202606031780501207654525.png&quot; alt=&quot;image.png&quot; width=&quot;618&quot; height=&quot;316&quot; border=&quot;0&quot; vspace=&quot;0&quot; title=&quot;image.png&quot; style=&quot;width: 618px; height: 316px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;再在该目录下新建一个file，记住一定是file，没有后缀名文件名叫xposed_init&lt;/p&gt;&lt;p&gt;其内为如下内容，其中com.xxx.xxx是你的包名，如果你不知道，你可以打开MainActivity.java中第一行，package com.xxx.xxx，那个就是你的包名，MainHook是我们的xposed类名，稍等再创建这个类&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;com.xxx.xxx.MainHook&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/06/202606031780501440114456.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;h2&gt;Xposed Hook代码&lt;/h2&gt;&lt;p&gt;在和MainActivity相同的目录下新建MainHook.java，代码如图，第一行是你的包名，记住不要全部复制嗷&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/06/202606031780501794914604.png&quot; alt=&quot;image.png&quot; width=&quot;840&quot; height=&quot;331&quot; border=&quot;0&quot; vspace=&quot;0&quot; title=&quot;image.png&quot; style=&quot;width: 840px; height: 331px;&quot;/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;package&amp;nbsp;com.yuer.study;//包名记得替换

import&amp;nbsp;de.robv.android.xposed.IXposedHookLoadPackage;
import&amp;nbsp;de.robv.android.xposed.XposedBridge;
import&amp;nbsp;de.robv.android.xposed.callbacks.XC_LoadPackage;

public&amp;nbsp;class&amp;nbsp;MainHook&amp;nbsp;implements&amp;nbsp;IXposedHookLoadPackage&amp;nbsp;{

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;handleLoadPackage(XC_LoadPackage.LoadPackageParam&amp;nbsp;lpparam)&amp;nbsp;throws&amp;nbsp;Throwable&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;XposedBridge.log(&amp;quot;yuerlv&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;&amp;quot;启动&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;lpparam.packageName&amp;nbsp;+&amp;nbsp;&amp;quot;&amp;nbsp;成功咯&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

}&lt;/pre&gt;&lt;h2&gt;运行&lt;/h2&gt;&lt;p&gt;然后你打开LSPosed，勾选需要的App，再把该模块打开，看日志即可&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/06/202606031780502160116683.png&quot; alt=&quot;image.png&quot; width=&quot;714&quot; height=&quot;162&quot; border=&quot;0&quot; vspace=&quot;0&quot; title=&quot;image.png&quot; style=&quot;width: 714px; height: 162px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Wed, 03 Jun 2026 23:12:21 +0800</pubDate></item><item><title>MySQL+Redis+RabbitMQ解决并发问题</title><link>https://www.anyuer.club/?id=292</link><description>&lt;h1&gt;引言&lt;/h1&gt;&lt;p&gt;由于业务不方便展示，此处特定构造了一个新的业务场景。&lt;/p&gt;&lt;p&gt;假设每个用户有一个uid字段和hot字段，游客可以为uid为1的用户点赞，点赞一次数值加1，一个游客还好，那万一有很多很多呢&lt;/p&gt;&lt;p&gt;我写了一个demo，未进行任何并发处理的源码已经分享，方便大家参考&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;https://github.com/Anyuer9837/ConcurrencyStudy&lt;/pre&gt;&lt;p&gt;其中数据库建议云的，家用的笔记本电脑或者台式电脑，一般来说性能都不错，很难压力测试，或者说效果不明显， 所以我留下了可以使用的MySQL服务器进行在src/main/resources/application.properties 里面&lt;/p&gt;&lt;p&gt;同时希望大佬可以手下留情，我这为爱发电，希望大家别搞破坏，和平交流学习！共同进步！&lt;/p&gt;&lt;h1&gt;问题分析&lt;/h1&gt;&lt;p&gt;其实问题的原因很简单，当有大规模用户同时对MySQL的某一行数据的每一个字段进行写入的时候，会出现异常问题，&lt;br/&gt;&lt;/p&gt;&lt;h1&gt;解决思路&lt;/h1&gt;&lt;p&gt;针对这种高并发单点读写的瓶颈，整体的应对策略是利用分布式锁控制并发、缓存承载高频读写、消息队列异步削峰落库以及异常反向补偿的组合方案。&lt;/p&gt;&lt;p&gt;程序开始先获取十五秒的分布式锁。这样做是为了让并发请求针对该用户串行排队，防止高并发在缓存失效时同时击穿到数据库，也避免了多线程交错计算导致的数据覆盖。&lt;/p&gt;&lt;p&gt;拿到锁后优先读取缓存，有数据则直接使用，无数据则去数据库查询基数并回填。优先读缓存利用了内存的高性能，缓存缺失时去数据库查询并在锁的保护下回填，确保了冷启动时只有一个线程访问数据库，绝对安全。随后程序在内存中将热度加一，并立刻写回缓存，让前端能毫秒级感知最新状态。&lt;/p&gt;&lt;p&gt;缓存更新后，程序将数据打包发送给消息队列，发送成功即对前端返回成功。这种设计不等待慢速的数据库事务提交，利用队列作为蓄水池平滑落库，切断了高并发流量对底层数据库的直接冲击，实现了流量削峰。&lt;/p&gt;&lt;p&gt;如果发送队列失败，程序会立刻捕获异常并执行缓存的原子递减，把刚才多加的数值原路减回去。这种反向补偿机制是为了在分布式系统遭遇局部网络故障时，及时撤销内存变更，保证缓存和数据库的数据最终一致性。&lt;/p&gt;&lt;p&gt;最后无论流程顺利还是抛出异常，程序都会在清理块中判断锁是否仍由当前线程持有，确认无误后再执行释放。这样可以防止当前线程因为自身卡顿导致锁超时后，去错误地释放正在保护其他线程的锁，完成了安全的生命周期闭环。&lt;/p&gt;&lt;h1&gt;核心代码&lt;/h1&gt;&lt;p&gt;代码已经贴到上方仓库的1.0分支，这里展示的是核心代码&lt;br/&gt;&lt;/p&gt;&lt;h2&gt;查询逻辑+业务逻辑+发送消息到队列&lt;/h2&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;boolean&amp;nbsp;updateHot(UserHot&amp;nbsp;userHot)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;cacheKey&amp;nbsp;=&amp;nbsp;&amp;quot;user:hot:&amp;quot;&amp;nbsp;+&amp;nbsp;userHot.getUid();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;lockKey&amp;nbsp;=&amp;nbsp;&amp;quot;lock:user-hot:&amp;quot;&amp;nbsp;+&amp;nbsp;userHot.getUid();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RLock&amp;nbsp;lock&amp;nbsp;=&amp;nbsp;redissonClient.getLock(lockKey);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;1.&amp;nbsp;尝试获取分布式锁，限时&amp;nbsp;5&amp;nbsp;秒
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(lock.tryLock(5,&amp;nbsp;TimeUnit.SECONDS))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int&amp;nbsp;newHot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;2.&amp;nbsp;隔离并发下的&amp;nbsp;Redis&amp;nbsp;操作
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;cachedHot&amp;nbsp;=&amp;nbsp;redisTemplate.opsForValue().get(cacheKey);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int&amp;nbsp;currentHot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(cachedHot&amp;nbsp;!=&amp;nbsp;null)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;currentHot&amp;nbsp;=&amp;nbsp;Integer.parseInt(cachedHot);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;else&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UserHot&amp;nbsp;dbData&amp;nbsp;=&amp;nbsp;userHotMapper.selectByPrimaryKey(userHot.getUid());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(dbData&amp;nbsp;==&amp;nbsp;null)&amp;nbsp;return&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;currentHot&amp;nbsp;=&amp;nbsp;dbData.getHot();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redisTemplate.opsForValue().set(cacheKey,&amp;nbsp;String.valueOf(currentHot));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;内存计算并回写&amp;nbsp;Redis
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;newHot&amp;nbsp;=&amp;nbsp;currentHot&amp;nbsp;+&amp;nbsp;1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redisTemplate.opsForValue().set(cacheKey,&amp;nbsp;String.valueOf(newHot));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;catch&amp;nbsp;(Exception&amp;nbsp;e)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.err.println(&amp;quot;【❌&amp;nbsp;Redis故障】操作Redis失败，原因:&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;e.getMessage());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;3.&amp;nbsp;隔离&amp;nbsp;MQ&amp;nbsp;消息发送
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&amp;nbsp;message&amp;nbsp;=&amp;nbsp;userHot.getUid()&amp;nbsp;+&amp;nbsp;&amp;quot;,&amp;quot;&amp;nbsp;+&amp;nbsp;newHot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rabbitTemplate.convertAndSend(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RabbitConfig.HOT_EXCHANGE,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RabbitConfig.HOT_ROUTING_KEY,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;message
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;catch&amp;nbsp;(Exception&amp;nbsp;e)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.err.println(&amp;quot;【MQ故障】消息发送到RabbitMQ失败！原因:&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;e.getMessage());

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;💡&amp;nbsp;开始执行回滚逻辑
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&amp;quot;【触发回滚】正在将&amp;nbsp;Redis&amp;nbsp;数据恢复原状...&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;使用&amp;nbsp;decrement&amp;nbsp;原子操作，把刚才加的&amp;nbsp;1&amp;nbsp;减回去
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redisTemplate.opsForValue().decrement(cacheKey);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&amp;quot;【回滚成功】Redis&amp;nbsp;数据已撤销，保证了数据一致性。&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;catch&amp;nbsp;(Exception&amp;nbsp;rollbackEx)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;🚨&amp;nbsp;极端边缘场景：刚才写&amp;nbsp;Redis&amp;nbsp;还好好的，回滚的时候&amp;nbsp;Redis&amp;nbsp;突然宕机或断网了！
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.err.println(&amp;quot;【致命灾难】MQ发送失败，且&amp;nbsp;Redis&amp;nbsp;回滚也失败！出现严重数据不一致！&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.err.println(&amp;quot;急需人工介入！出问题的&amp;nbsp;UID:&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;userHot.getUid()&amp;nbsp;+&amp;nbsp;&amp;quot;，报错:&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;rollbackEx.getMessage());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;真实生产环境中，这里通常会打印&amp;nbsp;Error&amp;nbsp;级别日志触发钉钉/邮件报警，
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;或者把这条失败记录写到一个本地磁盘日志文件里，等重启后人工修数据。
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;else&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&amp;quot;【锁竞争激烈】获取分布式锁超时，其他线程正占用锁，本次更新放弃。&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;catch&amp;nbsp;(InterruptedException&amp;nbsp;e)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&amp;quot;【线程中断】等待锁的过程中线程被中断:&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;e.getMessage());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread.currentThread().interrupt();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;finally&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;严格释放锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(lock.isHeldByCurrentThread())&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lock.unlock();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/pre&gt;&lt;h2&gt;消费者&lt;/h2&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@RabbitListener(queues&amp;nbsp;=&amp;nbsp;RabbitConfig.HOT_QUEUE)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;receiveUserHotMessage(String&amp;nbsp;message)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;1.&amp;nbsp;解析消息（把&amp;nbsp;&amp;quot;1,11&amp;quot;&amp;nbsp;拆成&amp;nbsp;uid=1,&amp;nbsp;hot=11）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String[]&amp;nbsp;parts&amp;nbsp;=&amp;nbsp;message.split(&amp;quot;,&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Integer&amp;nbsp;uid&amp;nbsp;=&amp;nbsp;Integer.parseInt(parts[0]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Integer&amp;nbsp;newHot&amp;nbsp;=&amp;nbsp;Integer.parseInt(parts[1]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UserHot&amp;nbsp;updateData&amp;nbsp;=&amp;nbsp;new&amp;nbsp;UserHot();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;updateData.setUid(uid);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;updateData.setHot(newHot);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;userHotMapper.updateByPrimaryKeySelective(updateData);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;System.out.println(&amp;quot;【MQ成功落盘】用户&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;uid&amp;nbsp;+&amp;nbsp;&amp;quot;&amp;nbsp;的热度已同步为&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;newHot);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;catch&amp;nbsp;(Exception&amp;nbsp;e)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.err.println(&amp;quot;【MQ消费失败】&amp;quot;&amp;nbsp;+&amp;nbsp;e.getMessage());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;注意：这里如果抛出异常，RabbitMQ&amp;nbsp;会自动把这条消息重新放回队列头部，实现自动重试！
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw&amp;nbsp;e;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Mon, 01 Jun 2026 13:56:22 +0800</pubDate></item><item><title>安卓设备翻墙后将代理分享给局域网其他设备</title><link>https://www.anyuer.club/?id=291</link><description>&lt;p&gt;找到你的翻墙软件，打开设置，允许来自局域网的连接打开。&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605311780203607697748.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;然后，其它设备找到wifi，代理改为手动，输入翻墙的局域网设备ip和端口&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605311780203509283365.jpg&quot; alt=&quot;Screenshot_2026-05-31-12-57-47-943_com.android.settings.jpg&quot; width=&quot;720&quot; height=&quot;1600&quot; border=&quot;0&quot; vspace=&quot;0&quot; title=&quot;Screenshot_2026-05-31-12-57-47-943_com.android.settings.jpg&quot; style=&quot;width: 720px; height: 1600px;&quot;/&gt;&lt;/p&gt;</description><pubDate>Sun, 31 May 2026 12:56:16 +0800</pubDate></item><item><title>Cloudflare Tunnel 局域网服务变到公网</title><link>https://www.anyuer.club/?id=290</link><description>&lt;p&gt;这一招真的是太屌了，之前还要用各种内网穿透的软件，什么花生壳啊之类的，等等，就算公开了，域名也不能自行绑定，但是Cloudflare Tunnel 打通了这个通道，而且过程非常方便，现在教大家跑通这个流程。&lt;/p&gt;&lt;h1&gt;Windows&lt;br/&gt;&lt;/h1&gt;&lt;p&gt;打开cloudflare官网&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;https://dash.cloudflare.com/&lt;/pre&gt;&lt;p&gt;创建隧道&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605311780204684838747.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;输入一个隧道名称&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605311780204785829748.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;然后，下载对应的配置工具&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605311780204831162907.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;下载完成后，双击运行。记得以管理员权限打开&lt;/p&gt;&lt;p&gt;然后输入命令，命令必须复制cloudflare发给你的&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605311780204971739830.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605311780205336114862.png&quot; alt=&quot;屏幕截图 2026-05-31 132839.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;然后你就会发现成功了，点击创建就可以了&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605311780205360501243.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;然后就是创建路由了，点击刚才的隧道，进去后点击添加路由&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605311780205412126740.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;然后选择本地已经开启的服务&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605311780205432391466.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;然后选择你在cloudflare绑定的域名，再加一个二级域名，再输入本地的服务，最后点击添加路由，就完事了&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605311780205487392559.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;然后就可以通过域名进行访问了。&lt;/p&gt;&lt;p&gt;但是现在目前来看，一个设备只能一个cloudflare服务，如果你要把当前的设备进行更换隧道，那么就必须卸载掉原有隧道才行&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;cloudflared&amp;nbsp;service&amp;nbsp;uninstall&lt;/pre&gt;&lt;h1&gt;Android&lt;/h1&gt;&lt;p&gt;我的发，太伟大了，这种服务也可以让termux部署，先输入如下命令&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;apt&amp;nbsp;install&amp;nbsp;cloudflared&lt;/pre&gt;&lt;p&gt;然后其他流程一模一样。。。。。。。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;ALTER&amp;nbsp;USER&amp;nbsp;&amp;#39;root&amp;#39;@&amp;#39;localhost&amp;#39;&amp;nbsp;IDENTIFIED&amp;nbsp;BY&amp;nbsp;&amp;#39;你的新密码&amp;#39;;
FLUSH&amp;nbsp;PRIVILEGES;&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Sat, 30 May 2026 22:55:15 +0800</pubDate></item><item><title>MyBatisCodeHelper免费版</title><link>https://www.anyuer.club/?id=289</link><description>&lt;p&gt;MyBatisCodeHelper好用是好用，就是不免费这太难受了，整理了一下大佬破解的免费的版本&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-basic&quot;&gt;通过网盘分享的文件：MyBatisCodeHelper-Pro-3.4.4_2321-2023.2-2025.1obfuscated.zip
链接:&amp;nbsp;https://pan.baidu.com/s/1Jccn2qWRoryGgBSHxGzLeQ?pwd=yuer&amp;nbsp;提取码:&amp;nbsp;yuer&amp;nbsp;
--来自百度网盘超级会员v4的分享&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Fri, 29 May 2026 16:01:57 +0800</pubDate></item><item><title>去掉Ai生成的ppt里面的水印</title><link>https://www.anyuer.club/?id=288</link><description>&lt;h1&gt;Ai网址是&lt;/h1&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;https://gamma.app/&lt;/pre&gt;&lt;h1&gt;原理介绍&lt;/h1&gt;&lt;p&gt;ppt、apk等文件其实都是能通过特定方式进行解压的，原因很简单，那么多图片文字等等资源都在一个文件格式里面，肯定是要把文件塞进去才行的，而我门的ppt或者pptx，你可以直接修改为zip，然后进行解压就好了。大原理是这样，而Ai的生成的ppt大部分水印其实是一张图片进行叠加的，解压了之后，进去替换掉对应的水印文件就好了&lt;/p&gt;&lt;h1&gt;具体教程&lt;/h1&gt;&lt;p&gt;先将文件后缀名修改为zip，再进行解压，然后打开如下目录&lt;br/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;\ppt\media&lt;/pre&gt;&lt;p&gt;查看每张图片，找到水印的图片，比如gamma的水印图片就是image2.png&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605211779349458384722.png&quot; alt=&quot;image2.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;然后随便利用一个空白图片进行替换，就比如我下面这个&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605211779349572737518.png&quot; alt=&quot;transparent.png&quot; width=&quot;100&quot; height=&quot;100&quot; border=&quot;0&quot; vspace=&quot;0&quot; title=&quot;transparent.png&quot; style=&quot;width: 100px; height: 100px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;额，它真的有，但是由于是空白的，所以你看不到，如果你看得到的话，到时候替换过去的图片你也就能看到了，所以肯定是不好的，这里提供下载链接&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;https://www.anyuer.club/zb_users/upload/2026/05/202605211779349572737518.png&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Thu, 21 May 2026 15:38:48 +0800</pubDate></item><item><title>Ubuntu linux 系统 通过swap增加虚拟内存</title><link>https://www.anyuer.club/?id=287</link><description>&lt;h1&gt;添加教程&lt;/h1&gt;&lt;p&gt;示例是添加2G的swap文件&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;1.创建&amp;nbsp;Swap&amp;nbsp;文件
sudo&amp;nbsp;fallocate&amp;nbsp;-l&amp;nbsp;2G&amp;nbsp;/swapfile2

2.设置安全权限（非常重要）
sudo&amp;nbsp;chmod&amp;nbsp;600&amp;nbsp;/swapfile2

3.初始化&amp;nbsp;Swap
sudo&amp;nbsp;mkswap&amp;nbsp;/swapfile2

4.启用&amp;nbsp;Swap
sudo&amp;nbsp;swapon&amp;nbsp;/swapfile2

5.设置开机自启
sudo&amp;nbsp;nano&amp;nbsp;/etc/fstab

6.末尾行加入
/swapfile2&amp;nbsp;none&amp;nbsp;swap&amp;nbsp;sw&amp;nbsp;0&amp;nbsp;0&lt;/pre&gt;&lt;h1&gt;检验成果&lt;/h1&gt;&lt;p&gt;此时输入&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;swapon&amp;nbsp;--show&lt;/pre&gt;&lt;p&gt;可以看到新添加的&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605201779270433633334.png&quot; alt=&quot;image.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Wed, 20 May 2026 17:42:04 +0800</pubDate></item><item><title>神画——魔术师心灵魔术教程</title><link>https://www.anyuer.club/?id=286</link><description>&lt;h1&gt;简介 ：&lt;/h1&gt;&lt;p&gt;一个神奇的心灵魔术，你可以提前猜到用户接下来要说的数字，可以直接用观众手机打开下方网址进行表演&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;www.anyuer.club/draw_board/&lt;/pre&gt;&lt;h1&gt;基础功能：&lt;/h1&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;颜色&amp;nbsp;-&amp;nbsp;点击颜色块选择画笔颜色（红、蓝、绿、黑）

笔刷&amp;nbsp;-&amp;nbsp;拖动滑块调节笔刷大小（1-60px）

撤销&amp;nbsp;-&amp;nbsp;撤销上一步操作（最多保存30步历史）

清除&amp;nbsp;-&amp;nbsp;清空画布内容

保存&amp;nbsp;PNG&amp;nbsp;-&amp;nbsp;将画作导出为PNG图片&lt;/pre&gt;&lt;h1&gt;魔术表演教程：&lt;br/&gt;&lt;/h1&gt;&lt;p&gt;1. 准备阶段 - 让观众从1-4中随机选择一个数字&lt;/p&gt;&lt;p&gt;2. 预言环节 - 告诉观众你已经提前知道答案并写在画板上（但不给观众看）&lt;/p&gt;&lt;p&gt;3. 假装作画 - 在观众看不到的地方，点击笔刷大小数值区域（例如&amp;quot;4px&amp;quot;）进入隐藏模式&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605201779259488728491.png&quot; alt=&quot;136fa7cb-9edb-4091-83d5-adcf09efaa79.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;4. 四宫格模式 - 系统进入四宫格模式，将手机背面朝向观众&lt;/p&gt;&lt;p&gt;5. 揭晓答案 - 询问观众他们选择的数字，然后点击对应四宫格位置，翻转手机给观众看答案！&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605201779259553388998.png&quot; alt=&quot;a12c5fc2-6b9e-45a9-824f-011d9d272c1c.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Wed, 20 May 2026 14:37:53 +0800</pubDate></item><item><title>神相——魔术师的 AR 卡牌应用</title><link>https://www.anyuer.club/?id=283</link><description>&lt;h1&gt;下载地址&lt;/h1&gt;&lt;pre class=&quot;prism-highlight&quot;&gt;链接:&amp;nbsp;https://pan.baidu.com/s/1xaaknh7a-EPOW75nTM6IlA?pwd=yuer&amp;nbsp;提取码:&amp;nbsp;yuer&lt;/pre&gt;&lt;h1&gt;详细使用教程&lt;/h1&gt;&lt;p&gt;两个链接地址任选其一，内容完全一致，哪个能打开用哪个&lt;br/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight&quot;&gt;https://github.com/Anyuer9837/magicCamera
https://notebook.anyuer.club/public.php?id=MagicCamera&lt;/pre&gt;&lt;h1&gt;简易使用教程&lt;/h1&gt;&lt;p&gt;首先点击快门键，屏幕会闪烁一下，这个时候屏幕进入花色选择状态，不会有任何提示，对应的区域就是对应的花色&lt;/p&gt;&lt;p&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/20260513225926177868436697861.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;选完花色后，再次进入点数选择模式，对应区域就是对应的点数&lt;/p&gt;&lt;p&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/20260513225919177868435977738.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;然后就可以进行卡牌替换了。&lt;/p&gt;&lt;h1&gt;效果如下&lt;/h1&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605191779184339298714.png&quot; alt=&quot;2ab906e7-cf3d-48eb-98bb-d71ee0020be2.png&quot; width=&quot;400&quot; height=&quot;711&quot; border=&quot;0&quot; vspace=&quot;0&quot; title=&quot;2ab906e7-cf3d-48eb-98bb-d71ee0020be2.png&quot; style=&quot;width: 400px; height: 711px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.anyuer.club/zb_users/upload/2026/05/202605191779184351622823.png&quot; alt=&quot;1de40d01-30d2-40a0-999d-d632b155ff2f.png&quot; width=&quot;400&quot; height=&quot;711&quot; border=&quot;0&quot; vspace=&quot;0&quot; title=&quot;1de40d01-30d2-40a0-999d-d632b155ff2f.png&quot; style=&quot;width: 400px; height: 711px;&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Thu, 14 May 2026 00:44:38 +0800</pubDate></item></channel></rss>