今天,我不自量力的面试了某大厂的java开发岗位,迎面走来一位风尘仆仆的中年男子,手里拿着屏幕还亮着的mac,他冲着我礼貌的笑了笑,然后说了句“不好意思,让你久等了”,然后示意我坐下,说:“我们开始吧。看了你的简历,觉得你对redis应该掌握的不错,我们今天就来讨论下redis......”。我想:“来就来,兵来将挡水来土掩”。
10年积累的网站设计、成都网站设计经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站制作后付款的网站建设流程,更有平桥免费网站建设让你可以放心的选择与我们合作。
Redis是什么
五种数据类型
数据类型应用场景总结
类型 | 简介 | 特性 | 场景 |
---|---|---|---|
string(字符串) | 二进制安全 | 可以包含任何数据,比如jpg图片或者序列化对象 | --- |
Hash(字典) | 键值对集合,即编程语言中的map类型 | 适合存储对象,并且可以像数据库中的update一个属性一样只修改某一项属性值 | 存储、读取、修改用户属性 |
List(列表) | 链表(双向链表) | 增删快,提供了操作某一元素的api | 最新消息排行;消息队列 |
set(集合) | hash表实现,元素不重复 | 添加、删除、查找的复杂度都是O(1),提供了求交集、并集、差集的操作 | 共同好友;利用唯一性,统计访问网站的所有Ip |
sorted set(有序集合) | 将set中的元素增加一个权重参数score,元素按score有序排列 | 数据插入集合时,已经进行了天然排序 | 排行榜;带权重的消息队列 |
Redis缓存
org.springframework.boot spring-boot-starter-data-redis org.apache.commons commons-pool2 org.springframework.boot spring-boot-starter-web org.springframework.session spring-session-data-redis org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test
- server:
- port: 8082
- servlet:
- session:
- timeout: 30ms
- spring:
- cache:
- type: redis
- redis:
- host: 127.0.0.1
- port: 6379
- password:
- # redis默认情况下有16个分片,这里配置具体使用的分片,默认为0
- database: 0
- lettuce:
- pool:
- # 连接池最大连接数(使用负数表示没有限制),默认8
- max-active: 100
创建实体类User.java
- public class User implements Serializable{
- private static final long serialVersionUID = 662692455422902539L;
- private Integer id;
- private String name;
- private Integer age;
- public User() {
- }
- public User(Integer id, String name, Integer age) {
- this.id = id;
- this.name = name;
- this.age = age;
- }
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Integer getAge() {
- return age;
- }
- public void setAge(Integer age) {
- this.age = age;
- }
- @Override
- public String toString() {
- return "User{" +
- "id=" + id +
- ", name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
RedisTemplate的使用方式
默认情况下的模板只能支持RedisTemplate
- @Configuration
- @AutoConfigureAfter(RedisAutoConfiguration.class)
- public class RedisCacheConfig {
- @Bean
- public RedisTemplate
redisCacheTemplate(LettuceConnectionFactory connectionFactory) { - RedisTemplate
template = new RedisTemplate<>(); - template.setKeySerializer(new StringRedisSerializer());
- template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
- template.setConnectionFactory(connectionFactory);
- return template;
- }
- }
测试类
- @RestController
- @RequestMapping("/user")
- public class UserController {
- public static Logger logger = LogManager.getLogger(UserController.class);
- @Autowired
- private StringRedisTemplate stringRedisTemplate;
- @Autowired
- private RedisTemplate
redisCacheTemplate; - @RequestMapping("/test")
- public void test() {
- redisCacheTemplate.opsForValue().set("userkey", new User(1, "张三", 25));
- User user = (User) redisCacheTemplate.opsForValue().get("userkey");
- logger.info("当前获取对象:{}", user.toString());
- }
然后在浏览器访问,观察后台日志 http://localhost:8082/user/test
使用spring cache集成redis
spring cache具备很好的灵活性,不仅能够使用SPEL(spring expression language)来定义缓存的key和各种condition,还提供了开箱即用的缓存临时存储方案,也支持和主流的专业缓存如EhCache、Redis、Guava的集成。定义接口UserService.java
- public interface UserService {
- User save(User user);
- void delete(int id);
- User get(Integer id);
- }
接口实现类UserServiceImpl.java
- @Service
- public class UserServiceImpl implements UserService{
- public static Logger logger = LogManager.getLogger(UserServiceImpl.class);
- private static Map
userMap = new HashMap<>(); - static {
- userMap.put(1, new User(1, "肖战", 25));
- userMap.put(2, new User(2, "王一博", 26));
- userMap.put(3, new User(3, "杨紫", 24));
- }
- @CachePut(value ="user", key = "#user.id")
- @Override
- public User save(User user) {
- userMap.put(user.getId(), user);
- logger.info("进入save方法,当前存储对象:{}", user.toString());
- return user;
- }
- @CacheEvict(value="user", key = "#id")
- @Override
- public void delete(int id) {
- userMap.remove(id);
- logger.info("进入delete方法,删除成功");
- }
- @Cacheable(value = "user", key = "#id")
- @Override
- public User get(Integer id) {
- logger.info("进入get方法,当前获取对象:{}", userMap.get(id)==null?null:userMap.get(id).toString());
- return userMap.get(id);
- }
- }
为了方便演示数据库的操作,这里直接定义了一个Map
- @RestController
- @RequestMapping("/user")
- public class UserController {
- public static Logger logger = LogManager.getLogger(UserController.class);
- @Autowired
- private StringRedisTemplate stringRedisTemplate;
- @Autowired
- private RedisTemplate
redisCacheTemplate; - @Autowired
- private UserService userService;
- @RequestMapping("/test")
- public void test() {
- redisCacheTemplate.opsForValue().set("userkey", new User(1, "张三", 25));
- User user = (User) redisCacheTemplate.opsForValue().get("userkey");
- logger.info("当前获取对象:{}", user.toString());
- }
- @RequestMapping("/add")
- public void add() {
- User user = userService.save(new User(4, "李现", 30));
- logger.info("添加的用户信息:{}",user.toString());
- }
- @RequestMapping("/delete")
- public void delete() {
- userService.delete(4);
- }
- @RequestMapping("/get/{id}")
- public void get(@PathVariable("id") String idStr) throws Exception{
- if (StringUtils.isBlank(idStr)) {
- throw new Exception("id为空");
- }
- Integer id = Integer.parseInt(idStr);
- User user = userService.get(id);
- logger.info("获取的用户信息:{}",user.toString());
- }
- }
用缓存要注意,启动类要加上一个注解开启缓存
- @SpringBootApplication(exclude=DataSourceAutoConfiguration.class)
- @EnableCaching
- public class Application {
- public static void main(String[] args) {
- SpringApplication.run(Application.class, args);
- }
- }
1、先调用添加接口:http://localhost:8082/user/add
2、再调用查询接口,查询id=4的用户信息:
可以看出,这里已经从缓存中获取数据了,因为上一步add方法已经把id=4的用户数据放入了redis缓存 3、调用删除方法,删除id=4的用户信息,同时清除缓存
3、调用删除方法,删除id=4的用户信息,同时清除缓存
4、再次调用查询接口,查询id=4的用户信息:
没有了缓存,所以进入了get方法,从userMap中获取。
缓存注解
1、@Cacheable 根据方法的请求参数对其结果进行缓存
2、@CachePut 根据方法的请求参数对其结果进行缓存,和@Cacheable不同的是,它每次都会触发真实方法的调用。参数描述见上。
3、@CacheEvict 根据条件对缓存进行清空
缓存问题
- setRedis(key, value, time+Math.random()*10000);
如果Redis是集群部署,将热点数据均匀分布在不同的Redis库中也能避免全部失效。或者设置热点数据永不过期,有更新操作就更新缓存就好了(比如运维更新了首页商品,那你刷下缓存就好了,不要设置过期时间),电商首页的数据也可以用这个操作,保险。
- public static String getData(String key) throws InterruptedException {
- //从Redis查询数据
- String result = getDataByKV(key);
- //参数校验
- if (StringUtils.isBlank(result)) {
- try {
- //获得锁
- if (reenLock.tryLock()) {
- //去数据库查询
- result = getDataByDB(key);
- //校验
- if (StringUtils.isNotBlank(result)) {
- //插进缓存
- setDataToKV(key, result);
- }
- } else {
- //睡一会再拿
- Thread.sleep(100L);
- result = getData(key);
- }
- } finally {
- //释放锁
- reenLock.unlock();
- }
- }
- return result;
- }
Redis为何这么快
Redis和Memcached的区别
淘汰策略
策略 | 描述 |
---|---|
volatile-lru | 从已设置过期时间的KV集中优先对最近最少使用(less recently used)的数据淘汰 |
volitile-ttl | 从已设置过期时间的KV集中优先对剩余时间短(time to live)的数据淘汰 |
volitile-random | 从已设置过期时间的KV集中随机选择数据淘汰 |
allkeys-lru | 从所有KV集中优先对最近最少使用(less recently used)的数据淘汰 |
allKeys-random | 从所有KV集中随机选择数据淘汰 |
noeviction | 不淘汰策略,若超过最大内存,返回错误信息 |
补充一下:Redis4.0加入了LFU(least frequency use)淘汰策略,包括volatile-lfu和allkeys-lfu,通过统计访问频率,将访问频率最少,即最不经常使用的KV淘汰。
持久化
- appendfsync yes
- appendfsync always #每次有数据修改发生时都会写入AOF文件。
- appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。
AOF可以做到全程持久化,只需要在配置中开启 appendonly yes。这样redis每执行一个修改数据的命令,都会把它添加到AOF文件中,当redis重启时,将会读取AOF文件进行重放,恢复到redis关闭前的最后时刻。
主从复制
分享名称:大厂面试!我和面试官之间关于Redis的一场对弈!
文章分享:http://www.csdahua.cn/qtweb/news12/261062.html
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网