今天,我不自量力的面试了某大厂的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。内容未经允许不得转载,或转载时需注明来源: 快上网