您的位置:首页 > 游戏 > 游戏 > 深圳设计公司深圳市广告设计公司_学设计的网站推荐_搜索引擎有哪些技巧_怎么在百度上发布自己的信息

深圳设计公司深圳市广告设计公司_学设计的网站推荐_搜索引擎有哪些技巧_怎么在百度上发布自己的信息

2025/3/10 6:06:52 来源:https://blog.csdn.net/qq_44820964/article/details/146139071  浏览:    关键词:深圳设计公司深圳市广告设计公司_学设计的网站推荐_搜索引擎有哪些技巧_怎么在百度上发布自己的信息
深圳设计公司深圳市广告设计公司_学设计的网站推荐_搜索引擎有哪些技巧_怎么在百度上发布自己的信息

在某个mysql+redis的业务中,有个根据id查询用户表数据逻辑,逻辑为:
1、先从redis中查询,如果redis中有,则返回redis结果
2、如果redis中没有,则查询mysql
3、将查出的结果放入redis中,并在方法中返回该查询结果
代码如下:

@Override
public User getUserById(Integer id) {User user = null;//1 拼装缓存keyString key = CACHE_KEY_USER + id;//2 查询redisuser = (User)redisTemplate.opsForValue().get(key);//3 redis无,进一步查询mysqlif (user == null) {//3.1 从mysql查出来useruser = this.userMapper.selectByPrimaryKey(id);//3.2 mysql有,redis无if (user != null) {//3.3 把mysql捞到的数据写入redis,方便下次查询能redis命中。redisTemplate.opsForValue().set(key, user);}}//4 redis有,直接返回return user;
}

这样写逻辑是没有问题的,但是如果以后有更多类似的需求,难道每个方法里面都要写这么长一串的重复判断逻辑吗?并且今天业务可能根据id来查询,明天需求变更,根据username查询,要改的话就比较麻烦了

因此,我们可以通过热拔插AOP+反射+Redis自定义缓存注解+SpringEL表达式,重构缓存代码,思路来源链接

通过编写通用组件,代码可精简到如下程度,以后有类似的mysql+redis需求,也只需要一个注解即可使用。通过修改#后面的值,保持值和方法传参名一致

@Override
@MyRedisCache(keyPrefix = "user",matchValue = "#id")
public User getUserById(Integer id){return userMapper.selectByPrimaryKey(id);
}

项目结构:标准的Springboot
在这里插入图片描述
pom.xml:引入mybatisplus、mysql驱动、lombok、redis、asepct相关

<?xml version="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.4.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>org.example</groupId><artifactId>my-redis</artifactId><version>0.0.1-SNAPSHOT</version><name>my-redis</name><description>my-redis</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>21</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.36</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.10.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.20</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.11</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.22.1</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

application.properties:配置了redis和sql数据源

spring.application.name=my-redis
server.port=8081spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/你的库?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
spring.datasource.username=你的账号
spring.datasource.password=你的密码spring.data.redis.database=0
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
spring.data.redis.password=
spring.data.redis.lettuce.pool.max-active=8
spring.data.redis.lettuce.pool.max-wait=-1ms
spring.data.redis.lettuce.pool.max-idle=8
spring.data.redis.lettuce.pool.min-idle=0

启动类:无改动,保持默认

package org.example.myredis;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class MyRedisApplication {public static void main(String[] args) {SpringApplication.run(MyRedisApplication.class, args);}}

RedisConfig:标准的序列化配置,注意额外加上注解@EnableAspectJAutoProxy,作用是开启AOP自动代理

package org.example.myredis.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;/**** @author xiajunfeng*/
@Configuration
@EnableAspectJAutoProxy //V2  开启AOP自动代理
public class RedisConfig {/*** @param lettuceConnectionFactory* @return redis序列化的工具配置类,下面这个请一定开启配置* 127.0.0.1:6379> keys ** 1) "ord:102"  序列化过* 2) "\xac\xed\x00\x05t\x00\aord:102"   野生,没有序列化过*/@Beanpublic RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(lettuceConnectionFactory);//设置key序列化方式stringredisTemplate.setKeySerializer(new StringRedisSerializer());//设置value的序列化方式jsonredisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}}

实体类User:记得在数据库中也创建表t_user,字段只有id和username即可

package org.example.myredis.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.io.Serializable;/*** @author xiajunfeng*/
@Data
@TableName("t_user")
public class User implements Serializable {@TableId(type = IdType.AUTO)private Integer id;@TableFieldprivate String username;}

UserController

package org.example.myredis.controller;import jakarta.annotation.Resource;
import org.example.myredis.entity.User;
import org.example.myredis.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;/*** UserController* @author xiajunfeng* @date 2025/03/09*/
@RestController
public class UserController {@Resourceprivate UserService service;@GetMapping(value = "/user/{id}")public User getUserById(@PathVariable("id") Integer id) {return service.getUserById(id);}}

UserService

package org.example.myredis.service;import org.example.myredis.entity.User;/*** @author xiajunfeng*/
public interface UserService {User getUserById(Integer id);}

UserServiceImpl:注意这里使用了自定义注解@MyRedisCache

package org.example.myredis.service.impl;import jakarta.annotation.Resource;
import org.example.myredis.annotation.MyRedisCache;
import org.example.myredis.entity.User;
import org.example.myredis.mapper.UserMapper;
import org.example.myredis.service.UserService;
import org.springframework.stereotype.Service;/*** UserServiceImpl* @author xiajunfeng* @date 2025/03/09*/
@Service
public class UserServiceImpl implements UserService {@Resourceprivate UserMapper userMapper;@Override@MyRedisCache(keyPrefix = "user",matchValue = "#id")public User getUserById(Integer id) {return userMapper.selectById(id);}}

UserMapper

package org.example.myredis.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.myredis.entity.User;/*** @author xiajunfeng*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

自定义注解MyRedisCache

package org.example.myredis.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** MyRedisCache* @author xiajunfeng* @date 2025/03/09*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRedisCache {String keyPrefix();String matchValue();}

最后一个就是关键的AOP:MyRedisCacheAspect

package org.example.myredis.aop;import jakarta.annotation.Resource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.example.myredis.annotation.MyRedisCache;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;/*** MyRedisCacheAspect* @author xiajunfeng* @date 2025/03/09*/
@Component
@Aspect
public class MyRedisCacheAspect {@Resourceprivate RedisTemplate redisTemplate;@Around("@annotation(org.example.myredis.annotation.MyRedisCache)")public Object doCache(ProceedingJoinPoint joinPoint) {Object result = null;try {//1 获得重载后的方法名MethodSignature signature = (MethodSignature)joinPoint.getSignature();Method method = signature.getMethod();//2 确定方法名后获得该方法上面配置的注解标签MyRedisCacheMyRedisCache myRedisCacheAnnotation = method.getAnnotation(MyRedisCache.class);//3 拿到了MyRedisCache这个注解标签,获得该注解上面配置的参数进行封装和调用String keyPrefix = myRedisCacheAnnotation.keyPrefix();String matchValueSpringEL = myRedisCacheAnnotation.matchValue();//4 SpringEL 解析器ExpressionParser parser = new SpelExpressionParser();//#idExpression expression = parser.parseExpression(matchValueSpringEL);EvaluationContext context = new StandardEvaluationContext();//5 获得方法里面的形参个数Object[] args = joinPoint.getArgs();DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();String[] parameterNames = discoverer.getParameterNames(method);for (int i = 0; i < parameterNames.length; i++) {System.out.println("获得方法里参数名和值: " + parameterNames[i] + "\t" + args[i].toString());context.setVariable(parameterNames[i], args[i].toString());}//6 通过上述,拼接redis的最终key形式String key = keyPrefix + ":" + expression.getValue(context);System.out.println("------拼接redis的最终key形式: " + key);//7 先去redis里面查询看有没有result = redisTemplate.opsForValue().get(key);if (result != null) {System.out.println("------redis里面有,我直接返回结果不再打扰mysql: " + result);return result;}//8 redis里面没有,去找mysql查询或叫进行后续业务逻辑//主业务逻辑查询mysql,放行result = joinPoint.proceed();//9 mysql步骤结束,还需要把结果存入redis一次,缓存补偿if (result != null) {System.out.println("------redis里面无,还需要把结果存入redis一次,缓存补偿: " + result);redisTemplate.opsForValue().set(key, result);}} catch (Throwable throwable) {throwable.printStackTrace();}return result;}}

最终测试:在数据库t_user表中添加id为1的数据,启动后端服务,访问localhost:8081/user/1,可在浏览器看到返回的User Json,同时控制台也能看到我们输出的相关文字,同时在Redis中也能找到id为1的user数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com