成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

Redis詳解 - SpringBoot整合Redis,RedisTemplate和注解兩種方式的使

SexySix / 555人閱讀

摘要:和注解的方法返回值要一致刪除緩存在需要刪除緩存的方法上加注解,執(zhí)行完這個方法之后會將中對應的記錄刪除。代表返回值,意思是當返回碼不等于時不緩存,也就是等于時才緩存。返回值特定值如果被設置了如果沒有被設置例子自動將對應到并且返回原來對應的。

本文主要講 Redis 的使用,如何與 SpringBoot 項目整合,如何使用注解方式和 RedisTemplate 方式實現(xiàn)緩存。最后會給一個用 Redis 實現(xiàn)分布式鎖,用在秒殺系統(tǒng)中的案例。

更多 Redis 的實際運用場景請關注開源項目 coderiver

項目地址:https://github.com/cachecats/...

一、NoSQL 概述 什么是 NoSQL ?

NoSQL(NoSQL = Not Only SQL ),意即“不僅僅是SQL”,泛指非關系型的數(shù)據(jù)庫。

為什么需要 NoSQL ?

隨著互聯(lián)網(wǎng)web2.0網(wǎng)站的興起,傳統(tǒng)的關系數(shù)據(jù)庫在應付web2.0網(wǎng)站,特別是超大規(guī)模和高并發(fā)的SNS類型的web2.0純動態(tài)網(wǎng)站已經(jīng)顯得力不從心,暴露了很多難以克服的問題,而非關系型的數(shù)據(jù)庫則由于其本身的特點得到了非常迅速的發(fā)展。NoSQL數(shù)據(jù)庫的產(chǎn)生就是為了解決大規(guī)模數(shù)據(jù)集合多重數(shù)據(jù)種類帶來的挑戰(zhàn),尤其是大數(shù)據(jù)應用難題。 -- 百度百科

NoSQL 數(shù)據(jù)庫的四大分類

鍵值(key-value)存儲

列存儲

文檔數(shù)據(jù)庫

圖形數(shù)據(jù)庫

分類 相關產(chǎn)品 典型應用 數(shù)據(jù)模型 優(yōu)點 缺點
鍵值(key-value) Tokyo、 Cabinet/Tyrant、Redis、Voldemort、Berkeley DB 內(nèi)容緩存,主要用于處理大量數(shù)據(jù)的高訪問負載 一系列鍵值對 快速查詢 存儲的數(shù)據(jù)缺少結(jié)構(gòu)化
列存儲數(shù)據(jù)庫 Cassandra, HBase, Riak 分布式的文件系統(tǒng) 以列簇式存儲,將同一列數(shù)據(jù)存在一起 查找速度快,可擴展性強,更容易進行分布式擴展 功能相對局限
文檔數(shù)據(jù)庫 CouchDB, MongoDB Web應用(與Key-Value類似,value是結(jié)構(gòu)化的) 一系列鍵值對 數(shù)據(jù)結(jié)構(gòu)要求不嚴格 查詢性能不高,而且缺乏統(tǒng)一的查詢語法
圖形(Graph)數(shù)據(jù)庫 Neo4J, InfoGrid, Infinite Graph 社交網(wǎng)絡,推薦系統(tǒng)等。專注于構(gòu)建關系圖譜 圖結(jié)構(gòu) 利用圖結(jié)構(gòu)相關算法 需要對整個圖做計算才能得出結(jié)果,不容易做分布式集群方案
NoSQL 的特點

易擴展

靈活的數(shù)據(jù)模型

大數(shù)據(jù)量,高性能

高可用

二、Redis 概述 Redis的應用場景

緩存

任務隊列

網(wǎng)站訪問統(tǒng)計

應用排行榜

數(shù)據(jù)過期處理

分布式集群架構(gòu)中的 session 分離

Redis 安裝

網(wǎng)上有很多 Redis 的安裝教程,這里就不多說了,只說下 Docker 的安裝方法:

Docker 安裝運行 Redis

docker run -d -p 6379:6379 redis:4.0.8

如果以后想啟動 Redis 服務,打開命令行,輸入以下命令即可。

redis-server

使用前先引入依賴


    org.springframework.boot
    spring-boot-starter-data-redis
三、注解方式使用 Redis 緩存

使用緩存有兩個前置步驟

pom.xml 引入依賴


    org.springframework.boot
    spring-boot-starter-data-redis

在啟動類上加注解 @EnableCaching

@SpringBootApplication
@EnableCaching
public class SellApplication {
    public static void main(String[] args) {
        SpringApplication.run(SellApplication.class, args);
    }
}

常用的注解有以下幾個

@Cacheable

屬性如下圖

用于查詢和添加緩存,第一次查詢的時候返回該方法返回值,并向 Redis 服務器保存數(shù)據(jù)。

以后調(diào)用該方法先從 Redis 中查是否有數(shù)據(jù),如果有直接返回 Redis 緩存的數(shù)據(jù),而不執(zhí)行方法里的代碼。如果沒有則正常執(zhí)行方法體中的代碼。

value 或 cacheNames 屬性做鍵,key 屬性則可以看作為 value 的子鍵, 一個 value 可以有多個 key 組成不同值存在 Redis 服務器。

驗證了下,value 和 cacheNames 的作用是一樣的,都是標識主鍵。兩個屬性不能同時定義,只能定義一個,否則會報錯。

condition 和 unless 是條件,后面會講用法。其他的幾個屬性不常用,其實我也不知道怎么用…

@CachePut

更新 Redis 中對應鍵的值。屬性和 @Cacheable 相同

@CacheEvict

刪除 Redis 中對應鍵的值。

3.1 添加緩存

在需要加緩存的方法上添加注解 @Cacheable(cacheNames = "product", key = "123"),

cacheNameskey 都必須填,如果不填 key ,默認的 key 是當前的方法名,更新緩存時會因為方法名不同而更新失敗。

如在訂單列表上加緩存

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @Cacheable(cacheNames = "product", key = "123")
    public ResultVO list() {

        // 1.查詢所有上架商品
        List productInfoList = productInfoService.findUpAll();

        // 2.查詢類目(一次性查詢)
        //用 java8 的特性獲取到上架商品的所有類型
        List categoryTypes = productInfoList.stream().map(e -> e.getCategoryType()).collect(Collectors.toList());
        List productCategoryList = categoryService.findByCategoryTypeIn(categoryTypes);

        List productVOList = new ArrayList<>();
        //數(shù)據(jù)拼裝
        for (ProductCategory category : productCategoryList) {
            ProductVO productVO = new ProductVO();
            //屬性拷貝
            BeanUtils.copyProperties(category, productVO);
            //把類型匹配的商品添加進去
            List productInfoVOList = new ArrayList<>();
            for (ProductInfo productInfo : productInfoList) {
                if (productInfo.getCategoryType().equals(category.getCategoryType())) {
                    ProductInfoVO productInfoVO = new ProductInfoVO();
                    BeanUtils.copyProperties(productInfo, productInfoVO);
                    productInfoVOList.add(productInfoVO);
                }
            }
            productVO.setProductInfoVOList(productInfoVOList);
            productVOList.add(productVO);
        }

        return ResultVOUtils.success(productVOList);
    }

可能會報如下錯誤

對象未序列化。讓對象實現(xiàn) Serializable 方法即可

@Data
public class ProductVO implements Serializable {
    
    private static final long serialVersionUID = 961235512220891746L;

    @JsonProperty("name")
    private String categoryName;

    @JsonProperty("type")
    private Integer categoryType;

    @JsonProperty("foods")
    private List productInfoVOList ;
}

生成唯一的 id 在 IDEA 里有一個插件:GenerateSerialVersionUID 比較方便。

重啟項目訪問訂單列表,在 rdm 里查看 Redis 緩存,有 product::123 說明緩存成功。

3.2 更新緩存

在需要更新緩存的方法上加注解: @CachePut(cacheNames = "prodcut", key = "123")

注意

cacheNameskey 要跟 @Cacheable() 里的一致,才會正確更新。

@CachePut()@Cacheable() 注解的方法返回值要一致

3.3 刪除緩存

在需要刪除緩存的方法上加注解:@CacheEvict(cacheNames = "prodcut", key = "123"),執(zhí)行完這個方法之后會將 Redis 中對應的記錄刪除。

3.4 其他常用功能

cacheNames 也可以統(tǒng)一寫在類上面, @CacheConfig(cacheNames = "product") ,具體的方法上就不用寫啦。

@CacheConfig(cacheNames = "product")
public class BuyerOrderController {
    @PostMapping("/cancel")
    @CachePut(key = "456")
    public ResultVO cancel(@RequestParam("openid") String openid,
                           @RequestParam("orderId") String orderId){
        buyerService.cancelOrder(openid, orderId);
        return ResultVOUtils.success();
    }
}

Key 也可以動態(tài)設置為方法的參數(shù)

@GetMapping("/detail")
@Cacheable(cacheNames = "prodcut", key = "#openid")
public ResultVO detail(@RequestParam("openid") String openid,
                             @RequestParam("orderId") String orderId){
    OrderDTO orderDTO = buyerService.findOrderOne(openid, orderId);
    return ResultVOUtils.success(orderDTO);
}

如果參數(shù)是個對象,也可以設置對象的某個屬性為 key。比如其中一個參數(shù)是 user 對象,key 可以寫成 key="#user.id"

緩存還可以設置條件。

設置當 openid 的長度大于3時才緩存

@GetMapping("/detail")
@Cacheable(cacheNames = "prodcut", key = "#openid", condition = "#openid.length > 3")
public ResultVO detail(@RequestParam("openid") String openid,
                                 @RequestParam("orderId") String orderId){
    OrderDTO orderDTO = buyerService.findOrderOne(openid, orderId);
    return ResultVOUtils.success(orderDTO);
}

還可以指定 unless 即條件不成立時緩存。#result 代表返回值,意思是當返回碼不等于 0 時不緩存,也就是等于 0 時才緩存。

@GetMapping("/detail")
@Cacheable(cacheNames = "prodcut", key = "#openid", condition = "#openid.length > 3", unless = "#result.code != 0")
public ResultVO detail(@RequestParam("openid") String openid,
                                 @RequestParam("orderId") String orderId){
    OrderDTO orderDTO = buyerService.findOrderOne(openid, orderId);
    return ResultVOUtils.success(orderDTO);
}

四、RedisTemplate 使用 Redis 緩存

與使用注解方式不同,注解方式可以零配置,只需引入依賴并在啟動類上加上 @EnableCaching 注解就可以使用;而使用 RedisTemplate 方式麻煩些,需要做一些配置。

4.1 Redis 配置

第一步還是引入依賴和在啟動類上加上 @EnableCaching 注解。

然后在 application.yml 文件中配置 Redis

spring:
  redis:
    port: 6379
    database: 0
    host: 127.0.0.1
    password:
    jedis:
      pool:
        max-active: 8
        max-wait: -1ms
        max-idle: 8
        min-idle: 0
    timeout: 5000ms

然后寫個 RedisConfig.java 配置類

package com.solo.coderiver.user.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
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.serializer.Jackson2JsonRedisSerializer;

import java.net.UnknownHostException;


@Configuration
public class RedisConfig {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate redisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        RedisTemplate template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(jackson2JsonRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

Redis 的配置就完成了。

4.2 Redis 的數(shù)據(jù)結(jié)構(gòu)類型

Redis 可以存儲鍵與5種不同數(shù)據(jù)結(jié)構(gòu)類型之間的映射,這5種數(shù)據(jù)結(jié)構(gòu)類型分別為String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)。

下面來對這5種數(shù)據(jù)結(jié)構(gòu)類型作簡單的介紹:

結(jié)構(gòu)類型 結(jié)構(gòu)存儲的值 結(jié)構(gòu)的讀寫能力
String 可以是字符串、整數(shù)或者浮點數(shù) 對整個字符串或者字符串的其中一部分執(zhí)行操作;對象和浮點數(shù)執(zhí)行自增(increment)或者自減(decrement)
List 一個鏈表,鏈表上的每個節(jié)點都包含了一個字符串 從鏈表的兩端推入或者彈出元素;根據(jù)偏移量對鏈表進行修剪(trim);讀取單個或者多個元素;根據(jù)值來查找或者移除元素
Set 包含字符串的無序收集器(unorderedcollection),并且被包含的每個字符串都是獨一無二的、各不相同 添加、獲取、移除單個元素;檢查一個元素是否存在于某個集合中;計算交集、并集、差集;從集合里賣弄隨機獲取元素
Hash 包含鍵值對的無序散列表 添加、獲取、移除單個鍵值對;獲取所有鍵值對
Zset 字符串成員(member)與浮點數(shù)分值(score)之間的有序映射,元素的排列順序由分值的大小決定 添加、獲取、刪除單個元素;根據(jù)分值范圍(range)或者成員來獲取元素
4.3 StringRedisTemplate 與 RedisTemplate

RedisTemplate 對五種數(shù)據(jù)結(jié)構(gòu)分別定義了操作

redisTemplate.opsForValue();

操作字符串

redisTemplate.opsForHash();

操作hash

redisTemplate.opsForList();

操作list

redisTemplate.opsForSet();

操作set

redisTemplate.opsForZSet();

操作有序set

如果操作字符串的話,建議用 StringRedisTemplate 。

StringRedisTemplate 與 RedisTemplate 的區(qū)別

StringRedisTemplate 繼承了 RedisTemplate。

RedisTemplate 是一個泛型類,而 StringRedisTemplate 則不是。

StringRedisTemplate 只能對 key=String,value=String 的鍵值對進行操作,RedisTemplate 可以對任何類型的 key-value 鍵值對操作。

他們各自序列化的方式不同,但最終都是得到了一個字節(jié)數(shù)組,殊途同歸,StringRedisTemplate 使用的是 StringRedisSerializer 類;RedisTemplate 使用的是 JdkSerializationRedisSerializer 類。反序列化,則是一個得到 String,一個得到 Object

兩者的數(shù)據(jù)是不共通的,StringRedisTemplate 只能管理 StringRedisTemplate 里面的數(shù)據(jù),RedisTemplate 只能管理 RedisTemplate中 的數(shù)據(jù)。

4.4 項目中使用

在需要使用 Redis 的地方,用 @Autowired 注入進來

@Autowired
RedisTemplate redisTemplate;
 
@Autowired
StringRedisTemplate stringRedisTemplate;

由于項目中暫時僅用到了 StringRedisTemplate 與 RedisTemplate 的 Hash 結(jié)構(gòu),StringRedisTemplate 比較簡單就不貼代碼了,下面僅對操作 Hash 進行舉例。

關于 RedisTemplate 的詳細用法,有一篇文章已經(jīng)講的很細很好了,我覺得沒必要再去寫了。傳送門

用 RedisTemplate 操作 Hash
package com.solo.coderiver.user.service.impl;

import com.solo.coderiver.user.dataobject.UserLike;
import com.solo.coderiver.user.dto.LikedCountDTO;
import com.solo.coderiver.user.enums.LikedStatusEnum;
import com.solo.coderiver.user.service.LikedService;
import com.solo.coderiver.user.service.RedisService;
import com.solo.coderiver.user.utils.RedisKeyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class RedisServiceImpl implements RedisService {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    LikedService likedService;

    @Override
    public void saveLiked2Redis(String likedUserId, String likedPostId) {
        String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
        redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, LikedStatusEnum.LIKE.getCode());
    }

    @Override
    public void unlikeFromRedis(String likedUserId, String likedPostId) {
        String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
        redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, LikedStatusEnum.UNLIKE.getCode());
    }

    @Override
    public void deleteLikedFromRedis(String likedUserId, String likedPostId) {
        String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
        redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
    }

    @Override
    public void incrementLikedCount(String likedUserId) {
        redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedUserId, 1);
    }

    @Override
    public void decrementLikedCount(String likedUserId) {
        redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedUserId, -1);
    }

    @Override
    public List getLikedDataFromRedis() {
        Cursor> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED, ScanOptions.NONE);
        List list = new ArrayList<>();
        while (cursor.hasNext()) {
            Map.Entry entry = cursor.next();
            String key = (String) entry.getKey();
            //分離出 likedUserId,likedPostId
            String[] split = key.split("::");
            String likedUserId = split[0];
            String likedPostId = split[1];
            Integer value = (Integer) entry.getValue();

            //組裝成 UserLike 對象
            UserLike userLike = new UserLike(likedUserId, likedPostId, value);
            list.add(userLike);

            //存到 list 后從 Redis 中刪除
            redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
        }

        return list;
    }

    @Override
    public List getLikedCountFromRedis() {
        Cursor> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, ScanOptions.NONE);
        List list = new ArrayList<>();
        while (cursor.hasNext()) {
            Map.Entry map = cursor.next();
            //將點贊數(shù)量存儲在 LikedCountDT
            String key = (String) map.getKey();
            LikedCountDTO dto = new LikedCountDTO(key, (Integer) map.getValue());
            list.add(dto);
            //從Redis中刪除這條記錄
            redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, key);
        }
        return list;
    }
}
五、Redis 實現(xiàn)分布式鎖

講完了基礎操作,再說個實戰(zhàn)運用,用Redis 實現(xiàn)分布式鎖 。

實現(xiàn)分布式鎖之前先看兩個 Redis 命令:

SETNX

key設置值為value,如果key不存在,這種情況下等同SET命令。 當key存在時,什么也不做。SETNX是”SET if Not eXists”的簡寫。

返回值

Integer reply, 特定值:

1 如果key被設置了

0 如果key沒有被設置

例子

redis> SETNX mykey "Hello"
(integer) 1
redis> SETNX mykey "World"
(integer) 0
redis> GET mykey
"Hello"
redis> 

GETSET

自動將key對應到value并且返回原來key對應的value。如果key存在但是對應的value不是字符串,就返回錯誤。

設計模式

GETSET可以和INCR一起使用實現(xiàn)支持重置的計數(shù)功能。舉個例子:每當有事件發(fā)生的時候,一段程序都會調(diào)用INCR給key mycounter加1,但是有時我們需要獲取計數(shù)器的值,并且自動將其重置為0。這可以通過GETSET mycounter “0”來實現(xiàn):

INCR mycounter
GETSET mycounter "0"
GET mycounter

返回值

bulk-string-reply: 返回之前的舊值,如果之前Key不存在將返回nil

例子

redis> INCR mycounter
(integer) 1
redis> GETSET mycounter "0"
"1"
redis> GET mycounter
"0"
redis>

這兩個命令在 java 中對應為 setIfAbsentgetAndSet

分布式鎖的實現(xiàn):

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

@Component
@Slf4j
public class RedisLock {

    @Autowired
    StringRedisTemplate redisTemplate;

    /**
     * 加鎖
     * @param key
     * @param value 當前時間 + 超時時間
     * @return
     */
    public boolean lock(String key, String value){
        if (redisTemplate.opsForValue().setIfAbsent(key, value)){
            return true;
        }

        //解決死鎖,且當多個線程同時來時,只會讓一個線程拿到鎖
        String currentValue = redisTemplate.opsForValue().get(key);
        //如果過期
        if (!StringUtils.isEmpty(currentValue) &&
                Long.parseLong(currentValue) < System.currentTimeMillis()){
            //獲取上一個鎖的時間
            String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
            if (StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)){
                return true;
            }
        }

        return false;
    }

    /**
     * 解鎖
     * @param key
     * @param value
     */
    public void unlock(String key, String value){

        try {
            String currentValue = redisTemplate.opsForValue().get(key);
            if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)){
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        }catch (Exception e){
            log.error("【redis鎖】解鎖失敗, {}", e);
        }
    }
}

使用:

/**
 * 模擬秒殺
 */
public class SecKillService {

    @Autowired
    RedisLock redisLock;

    //超時時間10s
    private static final int TIMEOUT = 10 * 1000;

    public void secKill(String productId){
        long time = System.currentTimeMillis() + TIMEOUT;
        //加鎖
        if (!redisLock.lock(productId, String.valueOf(time))){
            throw new SellException(101, "人太多了,等會兒再試吧~");
        }

        //具體的秒殺邏輯

        //解鎖
        redisLock.unlock(productId, String.valueOf(time));
    }
}

更多 Redis 的具體使用場景請關注開源項目 CodeRiver,致力于打造全平臺型全棧精品開源項目。

coderiver 中文名 河碼,是一個為程序員和設計師提供項目協(xié)作的平臺。無論你是前端、后端、移動端開發(fā)人員,或是設計師、產(chǎn)品經(jīng)理,都可以在平臺上發(fā)布項目,與志同道合的小伙伴一起協(xié)作完成項目。

coderiver河碼 類似程序員客棧,但主要目的是方便各細分領域人才之間技術交流,共同成長,多人協(xié)作完成項目。暫不涉及金錢交易。

計劃做成包含 pc端(Vue、React)、移動H5(Vue、React)、ReactNative混合開發(fā)、Android原生、微信小程序、java后端的全平臺型全棧項目,歡迎關注。

項目地址:https://github.com/cachecats/...

您的鼓勵是我前行最大的動力,歡迎點贊,歡迎送小星星? ~

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/72271.html

相關文章

  • springboot 整合redis

    摘要:與整合默認使用的是,相較于,是一個可伸縮的,線程安全的客戶端。在處理高并發(fā)方面有更多的優(yōu)勢。使用依賴主要需要的依賴為配置配置使用與整合可以在不更改現(xiàn)有代碼邏輯的基礎上,通過增加注解的方式,實現(xiàn)緩存。 springboot2.0 與redis整合默認使用的是Lettuce,相較于jedis,lettuce 是一個可伸縮的,線程安全的redis客戶端。在處理高并發(fā)方面有更多的優(yōu)勢。 Red...

    elarity 評論0 收藏0
  • springboot系列】springboot整合獨立模塊 redis 做緩存

    摘要:至此,已完成整合獨立模塊做緩存詳情請看地址相關文章系列整合獨立模塊 項目github地址:https://github.com/5-Ason/aso...具體可看 ./db/db-redis 和 ./db/db-cache 兩個模塊 // TODO 在整合redis之前需要先本地配置好redis環(huán)境,遲點有時間補一下linux下下載安裝配置redis 本文主要實現(xiàn)的是對數(shù)據(jù)操作進行獨立...

    qianfeng 評論0 收藏0
  • springboot系列】springboot整合獨立模塊 redis 做緩存

    摘要:至此,已完成整合獨立模塊做緩存詳情請看地址相關文章系列整合獨立模塊 項目github地址:https://github.com/5-Ason/aso...具體可看 ./db/db-redis 和 ./db/db-cache 兩個模塊 // TODO 在整合redis之前需要先本地配置好redis環(huán)境,遲點有時間補一下linux下下載安裝配置redis 本文主要實現(xiàn)的是對數(shù)據(jù)操作進行獨立...

    Jokcy 評論0 收藏0

發(fā)表評論

0條評論

SexySix

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<