redis 練習與緩存

題目:
模擬一個微博的熱搜
表: tb_news id title
Redis: zsetcss

例:
1.建立一個實體類 NewsEntityhtml

package com.lanou3g.redisdemo.entity;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.io.Serializable;

/**
 * 建立人: 武奇
 * 建立事件: 2019/6/26
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "tb_news")
public class NewsEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @Transient
    private Double score;


}

2 建立. NewsRepository 接口繼承JpaRepository 接口(繼承後可根據方法名自動生成sql語句)前端

package com.lanou3g.redisdemo.repository;

import com.lanou3g.redisdemo.entity.NewsEntity;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/**
 * 建立人: 武奇
 * 建立事件: 2019/6/26
 */
public interface NewsRepository extends JpaRepository<NewsEntity, Long> {

    List<NewsEntity> findByIdIn(List<Long> idList);
}

3.編寫前端導入JQ 向後臺發送請求java

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <title>新聞列表</title>
</head>
<body>

<div id="news-list"></div>

<script>
    
    $.get("/news/list", function (items) {
        
        const newsList = $("#news-list");
        for (const item of items) {
            //列出從數據庫中查出的數據
            const a = $("<a></a>").text(item.title);
            
            //點擊查出的數據獲取id 去redis中查出誰的點擊量最高
            a.click(function () {
                const data = {id: item.id};
                $.post("/news/like", data, function (resp) {
                    console.log("點同意功")
                })
            });

            //把每條數據放入div中 在放入br標籤使每條數據都換行
            newsList.append(a);
            newsList.append($("<br>"))
        }
    })


</script>

</body>
</html>

4.建立controller 層接收前端發送過來的請求jquery

@RestController
@RequestMapping("/news")
public class NewsController {

//    引入NewsService 接口
    @Resource
    private NewsService newsService;


//    查詢全部
    @RequestMapping("/list")
    public List<NewsEntity> list() {
        return this.newsService.findAll();
    }

//  增長點擊數量 (Id 的添加)
    @RequestMapping("/like")
    public Map<String, Object> like(Long id) {
        this.newsService.likeId(id);
        return Collections.singletonMap("message", "OK");
    }
//  向前端返回集合(id 的返回)
    @RequestMapping("/sort")
    public Collection<?> sort() {
        return this.newsService.getWithScoresId();
    }

建立 newservice 接口 (接口中寫了兩種添加 到 redis方式)redis

public interface NewsService {
//    查新全部新聞
    List<NewsEntity> findAll();
//  添加點擊數量(對象作法)
    void like(Long id);
//  返回點擊數量(對象作法)
    Set<?> getWithScores();
//  添加點擊數量(id 作法)
    void likeId(Long id);
//  返回點擊數量(id 作法)
    Collection<?> getWithScoresId();

建立 NewsService 接口的實現類spring

@Service("newsService")
public class NewsServiceImpl implements NewsService {

//    引入NewsRepository接口
    @Resource
    private NewsRepository newsRepository;

//    引入springframework.data.redis.core 包下的 實體類 RedisTemplate
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

//    查出全部
    @Override
    public List<NewsEntity> findAll() {
        return this.newsRepository.findAll();
    }

//    在redis中存入對象
    @Override
    public void like(Long id) {
        ZSetOperations<String, Object> opsZ = this.redisTemplate.opsForZSet();
//        使用id查詢全部
        Optional<NewsEntity> optional = this.newsRepository.findById(id);
//        若是optional有值存在
        if (optional.isPresent()) {
//            取出查出NewsEntity 點擊增長多少
            NewsEntity news = optional.get();
//            添加到redis 中  1,名字  2,對象  3每次
            opsZ.incrementScore("news:like", news, 1);
        }
    }


//  返回 按照scores排序好的數據
    @Override
    public Set<?> getWithScores() {
        ZSetOperations<String, Object> opsZ = this.redisTemplate.opsForZSet();
//        取出redis 中的按照scores排序好的數據  1,取出數據的名字  2,從0 開始  3,到第10 個結束
        Set<ZSetOperations.TypedTuple<Object>> set = opsZ.reverseRangeWithScores("news:like", 0, 10);
        return set;
    }



//    在redis中存入id
    @Override
    public void likeId(Long id) {
        ZSetOperations<String, Object> opsZ = this.redisTemplate.opsForZSet();
        opsZ.incrementScore("news:like:id", id, 1);
    }



//    從redis中取出 存入的id 與Scores
    @Override
    public Collection<?> getWithScoresId() {
        ZSetOperations<String, Object> opsZ = this.redisTemplate.opsForZSet();
//        取出存入id的集合
        Set<ZSetOperations.TypedTuple<Object>> tuple = opsZ.reverseRangeWithScores("news:like:id", 0, 10);
        // 這個tuple裏保存的關鍵信息是每一個新聞的分數和新聞的id的順序.
        List<NewsEntity> items = new ArrayList<>();
        for (ZSetOperations.TypedTuple<Object> item : tuple) {
            Long id = Long.parseLong(String.valueOf(item.getValue()));
//            使用id查詢 查詢這條新聞的全部信息
            Optional<NewsEntity> optional = this.newsRepository.findById(id);
//            若是返回的對象不爲空
            if (optional.isPresent()) {
                NewsEntity news = optional.get();
//                把分數加入對象
                news.setScore(item.getScore());
//                添加進list
                items.add(news);
            }

        }
        return items;
    }

建立 RedisConfig 配置 存儲 redis 時 存入對象的配置sql

package com.lanou3g.redisdemo.config;

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * 建立人: 武奇
 * 建立事件: 2019/6/25
 */
@Configuration
public class RedisConfig {

//    配置key的序列化
    @Bean
    public RedisSerializer keySerializer() {
        return new StringRedisSerializer();
    }
    //    配置value的序列化
    @Bean
    public RedisSerializer valueSerializer() {
        // 當向Redis中存儲一個對象時候,
        // 會把對象轉換爲json數據存儲到Redis中
        return new GenericJackson2JsonRedisSerializer();
    }

//
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(keySerializer());
        redisTemplate.setHashKeySerializer(keySerializer());
        // 若是不配置JSON的序列化, 還想保存對象,
        // 那麼前提是這個對象是能夠被序列化的, 也就是說
        // 對應的類必須是實現Serializable接口的
        // 若是須要使用JSON的序列化, 被保存的對象,
        // 必須得有默認的構造方法, 不然對象能被存上, 可是讀不出來
        redisTemplate.setValueSerializer(valueSerializer());
        redisTemplate.setHashValueSerializer(valueSerializer());
        return redisTemplate;
    }



    /*
    <bean id="keySerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>

    <bean id="redisTemplate" class="com.xxx.RedisTemplate">
        <property key="connectionFactory" ref="redisConnectionFactory"/>
        <property key="keySerializer" ref="keySerializer" />
        <property key="hashKeySerializer" ref="keySerializer" />
    </bean>

  */
}

這樣 模擬的微博熱搜 就寫完了數據庫


Redis緩存json

須要在 application.yml 裏配置(其實能夠不配置,只要導包時 有導入redis 包 那麼他會自動匹配能夠不寫)

#如果已經導入redis框架 能夠不寫 (下面一段)它默認就是redis
  redis:
    host: localhost
    port: 6379
  #選擇緩存器是 誰的緩存(可不寫 加入redis框架後默認是redis
  #如不加redis框架也能夠用緩存,會默認用simple
  cache:
    type: redis

在SpringBoot 項目開始建立時,自動建立的實體類中寫 開始緩存的註解

package com.lanou3g.redisdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
//啓用緩存
@EnableCaching
public class RedisDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedisDemoApplication.class, args);
    }

}

在cotroller 層 中 作緩存

//  @Cacheable 該方法支持緩存  cacheNames緩存的名字
    @Cacheable(cacheNames = "cache:news")
//    在建立工程最初的被建立的實體類中開啓緩存加上 @EnableCaching 註解
    @RequestMapping("/{id}")
    public NewsEntity getOne(@PathVariable Long id) {
        return this.newsService.findById(id);
    }


//    再緩存中真正的key 是由兩部分組成的:
//    第一部分是緩存的名字,也cacheNames就是相應的值
//    第二部分是緩存的key, 也就是key的屬性

    //在作數據更新的時候須要緩存進行同步
    //    @CacheEvict刪掉某個緩存
    @CacheEvict(cacheNames = "cache:news",key = "#news.id")
    @RequestMapping("/update")
    public NewsEntity update(NewsEntity news) {

        return this.newsService.update(news);
    }

//    添加數據
//    @CachePut  直接更新緩存
//    key的參數是 返回值的id
    @CachePut(cacheNames = "cache:news",key = "#result.id")
    @RequestMapping("/save")
    public  NewsEntity save(NewsEntity news){

        return NewsEntity.builder()
                .id(10001L)
                .build();
    }

只要加上註解 redis 就會開始緩存
@Cacheable 該方法支持緩存
@CachePut 直接更新緩存
@CacheEvict刪掉某個緩存

緩存相關的註解,不必定非寫在controller層
寫在service或Dao層均可以
根據實際需求靈活使用

service 層和之前同樣 寫

相關文章
相關標籤/搜索