使用Redis做缓存的小案例

        如果不了解Redis,可以查看本人博客:Redis入门

        Redis基于内存,因此查询速度快,常常可以用来作为缓存使用,缓存就是我们在内存中开辟一段区域来存储我们查询比较频繁的数据,这样,我们在下一次查询的时候,会直接去内存中查询,如果命中(查询到),就直接返回,否则就去数据库等在磁盘位置存储的数据进行查询,去磁盘硬盘等位置查询数据就比较慢了。因此,用好缓存对于我们的用户体验也是很重要的。

        本文基于springboot+mybatisplus+Redis进行实现。

        首先创建一个springboot项目:

        不勾选依赖:

        导入依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        配置application.yaml

spring:
  redis:
    host: localhost
    port: 6379
    password: 123456
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/hongyan_sso?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true

        编写实体类:

package com.qcby.springbootdata.pojo;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@TableName("t_user")
@Data
public class User {
    private Long id;
    private String userName;
    private String password;
    private String nickName;
}

        编写mapper:

package com.qcby.springbootdata.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qcby.springbootdata.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.tomcat.websocket.BackgroundProcess;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

        编写controller:

package com.qcby.springbootdata.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.qcby.springbootdata.mapper.UserMapper;
import com.qcby.springbootdata.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;

@RestController
@Slf4j
public class UserController {

    @Resource
    private UserMapper userMapper;
    @Resource
    private RedisTemplate<String,String> redisTemplate;

    @GetMapping("/get-user-by-nick")
    public String getUserByNick(Long  id){
        String key = buildKey(String.valueOf(id));
        if(Boolean.TRUE.equals(redisTemplate.hasKey(key))){
            log.info("命中缓存,id:{}",id);
            return redisTemplate.boundValueOps(key).get();
        }
        User userPO = userMapper.selectById(id);
        if(userPO == null){
            redisTemplate.boundValueOps(key).set("暂无此人");
            return "暂无此人";
        }
        redisTemplate.boundValueOps(key).set(userPO.toString());
        return userPO.toString();
    }

    /**
     * 更新用户
     * 一般情况下,修改后删除就行了
     * 但是并发比较高,而且对数据比较敏感,比如说金钱,需要双删
     *
     * @param userId   用户id
     * @param nickName 尼克名字
     * @return {@link String}
     * @throws InterruptedException 中断异常
     */
    @GetMapping("/update-user-by-nick")
    public String updateUser(Long userId,String nickName) throws InterruptedException {
        User userPO = new User();
        userPO.setId(userId);
        userPO.setNickName(nickName);
        //这一步删除是为了保证,当sql指令发送给mysql以后,查询出来的值还是旧的
        redisTemplate.delete(buildKey(userId.toString()));
        userMapper.updateById(userPO);
        //这一步是为保证在sql指定发送给mysql的时候,来了查询,如果说这个时候的查寻还是修改之前的,导致缓存不更新
        redisTemplate.delete(buildKey(userId.toString()));
        return "22";
    }


    /**
     * 缓存预热
     */
    @PostConstruct
    public void initCache(){
        log.info("=========进行缓存预热=======================");
        List<Long> id  = Arrays.asList(101110L,101112L,101116L,101118L);
        List<User> userPOS = userMapper.selectList(new LambdaQueryWrapper<User>().in(User::getId, id));
        userPOS.stream().forEach(item->{redisTemplate.boundValueOps(buildKey(item.getId().toString())).set(item.toString());});

    }

    private String buildKey(String Id){
        return "user:Id_"+Id;
    }
}

        我们看一下controller中的思路:

        ①.@GetMapping("/get-user-by-nick")
            public String getUserByNick(Long  id)

        这个方法首先根据给出的查询参数构造Redis的key,我们查询Redis或者存Redis数据通常会构造一个key,按照这个key来存储值。

        首先从Redis数据库中查询,是否存在该查询结果的数据,如果存有,就直接拿取返回即可,否则走下一步。

        然后从数据库中查询需要的数据,首先判断这个数据是否存在,如果存在就存入Redis该数据值,否则说明不存在,直接存储“无此数据”即可。

        这个函数的大体思路就是,有数据就拿,没数据就存一个下次方便拿。

        ②.@GetMapping("/update-user-by-nick")
            public String updateUser(Long userId,String nickName)

        这个函数就是用来更新数据库数据,并且做到数据库与缓存之间保持同步。主要是考虑并发情况下,保证缓存数据和数据库数据的最终一致性。更新前删除缓存中的数据,保证尽可能的让其他进程或线程感知到数据库变化,进而在缓存中没有命中,进数据库中查询数据,此时,数据可能已经被更新了,或者还没有更新。

        第二次删除就是为了保证数据更新以后,删除缓存中数据,让其他进程或线程在缓存中无命中,进而进入数据库读取最新的数据,保证了最终一致性。

        ③.@PostConstruct
            public void initCache()

        这个方法主要是做缓存预热,在查询数据之前,预先将访问频繁的数据存入缓存,进而提高缓存命中,提高查询效率。

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用 Redis 缓存的 Laravel 示例: 1. 安装 Redis 在 Laravel 中使用 Redis 需要先安装 Redis 扩展和 Predis 客户端库。可以通过以下命令安装: ```bash $ sudo apt-get install redis-server $ composer require predis/predis ``` 2. 配置 Redis 在 Laravel 中配置 Redis 需要在 `config/database.php` 文件中添加 Redis 的连接信息。可以参考以下示例: ```php 'redis' => [ 'client' => 'predis', 'default' => [ 'host' => env('REDIS_HOST', '127.0.0.1'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 0, ], ], ``` 3. 使用 Redis 缓存 在 Laravel 中使用 Redis 缓存可以使用 `Cache` Facade。可以参考以下示例: ```php use Illuminate\Support\Facades\Cache; // 缓存数据 Cache::put('key', 'value', $minutes); // 获取缓存数据 $value = Cache::get('key'); // 删除缓存数据 Cache::forget('key'); ``` 4. 使用 Redis Session 存储 在 Laravel 中使用 Redis Session 存储也很简单,只需要在 `config/session.php` 文件中修改 `driver` 为 `redis`,并配置 Redis 连接信息即可。可以参考以下示例: ```php 'driver' => env('SESSION_DRIVER', 'file'), 'connection' => env('SESSION_CONNECTION', 'default'), 'table' => 'sessions', 'store' => env('SESSION_STORE', null), 'lottery' => [2, 100], 'lifetime' => 120, 'expire_on_close' => false, 'encrypt' => false, 'files' => storage_path('framework/sessions'), 'cookie' => env( 'SESSION_COOKIE', Str::slug(env('APP_NAME', 'laravel'), '_').'_session' ), 'path' => '/', 'domain' => env('SESSION_DOMAIN', null), 'secure' => env('SESSION_SECURE_COOKIE'), 'http_only' => true, 'same_site' => 'lax', ``` 以上就是一个简单的 Laravel 使用 Redis 的示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值