Redis的学习

一:redis的初始

  1. 什么是redis?
    redis是一种Nosql类型的数据库。并且它也作为一种key-value的存储系统。它很好的补充了关系数据库的一些缺陷,以及一些key-value存储的不足,尤其是在数据类型上表现更多,它的数据存储类型包括:String(字符串)list(链表),set(集合)(zset,sortedset),hash(哈希)。

  2. 为什么要使用redis(它的功效是什么)
    (1)redis的数据类型丰富,这使得它在解决数据存储问题更加灵活
    (2)redis是将数据直接完全的保存在内存中,只需要在磁盘进行持久化,这使得它运行速度非常快,吞吐量大
    (3)它可以从主机上复制任意数量数据到从机,即保持主从同步。所以它可以作为缓存配置。

  3. redis安装配置
    在windows下安装配置,以及在linux安装配置。在官网上下载按步骤安装。
    redis配置参数,如果在java,redis.properties.

  4. redis基础命令
    set key value –设置键值
    get key –获取对应的键值
    getset key filed –设置新的键值并返回旧的键值
    hget key filed

    del key –删除key和关联值
    hdel key value 删除列表对应的字段值。

    incr key –以key所对应的值的数字值开始进行递增
    decr key –以key所对应的值的数字开始进行递减
    incrby key num 一以指定的值num座递增,并返回结果
    decrby key num –以指定的值num座递减,并返回结果
    -如果key不存在,或者key所对应的值的类型不正确 则将key所对应的值置为0 再进行操作

    Exists key –判断key是否存在
    Hexists key field –判断key或者字段是否存在

    help
    help del –查看命令帮助
    expire key seconds –设置key的过期时间
    quit –退出redis的客户端

二:redis与spring整合

1.使用redisson操纵redis,引用
http://blog.csdn.net/undergrowth/article/details/46301559

package com.undergrowth;  

import org.redisson.Config;  
import org.redisson.Redisson;  
import org.redisson.core.RAtomicLong;  
import org.redisson.core.RBucket;  
import org.redisson.core.RCountDownLatch;  
import org.redisson.core.RDeque;  
import org.redisson.core.RList;  
import org.redisson.core.RLock;  
import org.redisson.core.RMap;  
import org.redisson.core.RQueue;  
import org.redisson.core.RSet;  
import org.redisson.core.RSortedSet;  
import org.redisson.core.RTopic;  

/*** 
 * Redis client的辅助工具类 
 * 用于连接Redis服务器 创建不同的Redis Server对应的客户端对象 
 * @author u1 
 * 
 */  
public class RedisUtils {  

    private static RedisUtils redisUtils;  

    private RedisUtils(){}  

    /** 
     * 提供单例模式 
     * @return 
     */  
    public static RedisUtils getInstance(){  
        if(redisUtils==null)   
            synchronized (RedisUtils.class) {  
                if(redisUtils==null) redisUtils=new RedisUtils();  
            }  
        return redisUtils;  
    }  


    /** 
     * 使用config创建Redisson 
     * Redisson是用于连接Redis Server的基础类 
     * @param config 
     * @return 
     */  
    public Redisson getRedisson(Config config){  
        Redisson redisson=Redisson.create(config);  
        System.out.println("成功连接Redis Server");  
        return redisson;  
    }   

    /** 
     * 使用ip地址和端口创建Redisson 
     * @param ip 
     * @param port 
     * @return 
     */  
    public Redisson getRedisson(String ip,String port){  
        Config config=new Config();  
        config.useSingleServer().setAddress(ip+":"+port);  
        Redisson redisson=Redisson.create(config);  
        System.out.println("成功连接Redis Server"+"\t"+"连接"+ip+":"+port+"服务器");  
        return redisson;  
    }  

    /** 
     * 关闭Redisson客户端连接 
     * @param redisson 
     */  
    public void closeRedisson(Redisson redisson){  
        redisson.shutdown();  
        System.out.println("成功关闭Redis Client连接");  
    }  

    /** 
     * 获取字符串对象 
     * @param redisson 
     * @param t 
     * @param objectName 
     * @return 
     */  
    public <T> RBucket<T> getRBucket(Redisson redisson,String objectName){  
        RBucket<T> bucket=redisson.getBucket(objectName);  
        return bucket;  
    }  

    /** 
     * 获取Map对象 
     * @param redisson 
     * @param objectName 
     * @return 
     */  
    public <K,V> RMap<K, V> getRMap(Redisson redisson,String objectName){  
        RMap<K, V> map=redisson.getMap(objectName);  
        return map;  
    }  

    /** 
     * 获取有序集合 
     * @param redisson 
     * @param objectName 
     * @return 
     */  
    public <V> RSortedSet<V> getRSortedSet(Redisson redisson,String objectName){  
        RSortedSet<V> sortedSet=redisson.getSortedSet(objectName);  
        return sortedSet;  
    }  

    /** 
     * 获取集合 
     * @param redisson 
     * @param objectName 
     * @return 
     */  
    public <V> RSet<V> getRSet(Redisson redisson,String objectName){  
        RSet<V> rSet=redisson.getSet(objectName);  
        return rSet;  
    }  

    /** 
     * 获取列表 
     * @param redisson 
     * @param objectName 
     * @return 
     */  
    public <V> RList<V> getRList(Redisson redisson,String objectName){  
        RList<V> rList=redisson.getList(objectName);  
        return rList;  
    }  

    /** 
     * 获取队列 
     * @param redisson 
     * @param objectName 
     * @return 
     */  
    public <V> RQueue<V> getRQueue(Redisson redisson,String objectName){  
        RQueue<V> rQueue=redisson.getQueue(objectName);  
        return rQueue;  
    }  

    /** 
     * 获取双端队列 
     * @param redisson 
     * @param objectName 
     * @return 
     */  
    public <V> RDeque<V> getRDeque(Redisson redisson,String objectName){  
        RDeque<V> rDeque=redisson.getDeque(objectName);  
        return rDeque;  
    }  

    /** 
     * 此方法不可用在Redisson 1.2 中  
     * 在1.2.2版本中 可用 
     * @param redisson 
     * @param objectName 
     * @return 
     */  
    /** 
    public <V> RBlockingQueue<V> getRBlockingQueue(Redisson redisson,String objectName){ 
        RBlockingQueue rb=redisson.getBlockingQueue(objectName); 
        return rb; 
    }*/  

    /** 
     * 获取锁 
     * @param redisson 
     * @param objectName 
     * @return 
     */  
    public RLock getRLock(Redisson redisson,String objectName){  
        RLock rLock=redisson.getLock(objectName);  
        return rLock;  
    }  

    /** 
     * 获取原子数 
     * @param redisson 
     * @param objectName 
     * @return 
     */  
    public RAtomicLong getRAtomicLong(Redisson redisson,String objectName){  
        RAtomicLong rAtomicLong=redisson.getAtomicLong(objectName);  
        return rAtomicLong;  
    }  

    /** 
     * 获取记数锁 
     * @param redisson 
     * @param objectName 
     * @return 
     */  
    public RCountDownLatch getRCountDownLatch(Redisson redisson,String objectName){  
        RCountDownLatch rCountDownLatch=redisson.getCountDownLatch(objectName);  
        return rCountDownLatch;  
    }  

    /** 
     * 获取消息的Topic 
     * @param redisson 
     * @param objectName 
     * @return 
     */  
    public <M> RTopic<M> getRTopic(Redisson redisson,String objectName){  
         RTopic<M> rTopic=redisson.getTopic(objectName);  
         return rTopic;  
    }  


}  

测试代码
[java] view plain copy
import io.netty.util.concurrent.Future;  

import java.util.Arrays;  
import java.util.Collection;  
import java.util.concurrent.ExecutionException;  
import java.util.concurrent.TimeUnit;  

import org.junit.After;  
import org.junit.Before;  
import org.junit.Test;  
import org.redisson.Redisson;  
import org.redisson.core.MessageListener;  
import org.redisson.core.RAtomicLong;  
import org.redisson.core.RBucket;  
import org.redisson.core.RCountDownLatch;  
import org.redisson.core.RDeque;  
import org.redisson.core.RList;  
import org.redisson.core.RLock;  
import org.redisson.core.RMap;  
import org.redisson.core.RQueue;  
import org.redisson.core.RSet;  
import org.redisson.core.RSortedSet;  
import org.redisson.core.RTopic;  

import com.undergrowth.RedisUtils;  

public class RedisUtilsTest {  

    Redisson redisson;  

    /** 
     * 每次在测试方法运行之前 运行此方法 
     * 创建客户端连接服务器的redisson对象 
     */  
    @Before  
    public void before() {  
        String ip = "192.168.1.160";  
        String port = "6379";  
        redisson = RedisUtils.getInstance().getRedisson(ip, port);  
    }  

    /** 
     * 每次测试方法运行完之后 运行此方法 
     * 用于关闭客户端连接服务器的redisson对象 
     */  
    @After  
    public void after(){  
        RedisUtils.getInstance().closeRedisson(redisson);  
    }  

    /** 
     * RBucket 映射为 redis server 的 string 类型 
     * 只能存放最后存储的一个字符串 
     * redis server 命令: 
     * 查看所有键---->keys * 
     * 查看key的类型--->type testBucket 
     * 查看key的值 ---->get testBucket 
     */  
    @Test  
    public void testGetRBucket() {  
        RBucket<String> rBucket=RedisUtils.getInstance().getRBucket(redisson, "testBucket");  
        //同步放置  
        rBucket.set("redisBucketASync");  
        //异步放置  
        rBucket.setAsync("测试");  
        String bucketString=rBucket.get();  
        System.out.println(bucketString);  
    }  

    /** 
     * RMap  映射为  redis server 的 hash 类型 
     * 分为 
     * put(返回键值) 、 fast(返回状态) 
     * 同步    异步 
     * redis server 命令: 
     * 查看所有键---->keys * 
     * 查看key的类型--->type testMap 
     * 查看key的值 ---->hgetall testMap 
     * @throws InterruptedException 
     * @throws ExecutionException 
     */  
    @Test  
    public void testGetRMap() throws InterruptedException, ExecutionException {  
        RMap<String, Integer> rMap=RedisUtils.getInstance().getRMap(redisson, "testMap");  
        //清除集合  
        rMap.clear();  
        //添加key-value 返回之前关联过的值  
        Integer firrtInteger=rMap.put("111", 111);  
        System.out.println(firrtInteger);  
        //添加key-value 返回之前关联过的值  
        Integer secondInteger=rMap.putIfAbsent("222", 222);  
        System.out.println(secondInteger);  
        //移除key-value  
        Integer thirdInteger=rMap.remove("222");  
        System.out.println(thirdInteger);  
        //添加key-value 不返回之前关联过的值  
        boolean third=rMap.fastPut("333", 333);  
        System.out.println(third);  
        Future<Boolean> fiveFuture=rMap.fastPutAsync("444", 444);  
        System.out.println(fiveFuture.isSuccess());  
        //异步移除key  
        Future<Long> sixFuture=rMap.fastRemoveAsync("444");  
        System.out.println(String.valueOf(sixFuture.get()));  
        //遍历集合  
        for(String key :rMap.keySet()){  
            System.out.println(key+":"+rMap.get(key));  
        }  

    }  

    /** 
     * RSortedSet 映射为 redis server 的 list 类型 
     * 存储以有序集合的形式存放 
     *  redis server 命令: 
     * 查看所有键---->keys * 
     * 查看key的类型--->type testSortedSet 
     * 查看key的值 ---->lrange testSortedSet 0 10 
     */  
    @Test  
    public void testGetRSortedSet() {  
        RSortedSet<Integer> rSortedSet=RedisUtils.getInstance().getRSortedSet(redisson, "testSortedSet");  
        //清除集合  
        rSortedSet.clear();  
        rSortedSet.add(45);  
        rSortedSet.add(12);  
        rSortedSet.addAsync(45);  
        rSortedSet.add(100);  
        //输出结果集  
        System.out.println(Arrays.toString(rSortedSet.toArray()));;  
    }  

    /** 
     * RSet 映射为 redis server 的set 类型 
     *  redis server 命令: 
     * 查看所有键---->keys * 
     * 查看key的类型--->type testSet 
     * 查看key的值 ---->smembers testSet  
     */  
    @Test  
    public void testGetRSet() {  
        RSet<Integer> rSet=RedisUtils.getInstance().getRSet(redisson, "testSet");  
        //清除集合  
        rSet.clear();  
        Collection<Integer> c=Arrays.asList(12,45,12,34,56,78);  
        rSet.addAll(c);  
        //输出结果集  
        System.out.println(Arrays.toString(rSet.toArray()));  
    }  

    /** 
     * RList 映射为 redis server的list类型 
     *  redis server 命令: 
     * 查看所有键---->keys * 
     * 查看key的类型--->type testList 
     * 查看key的值 ---->lrange testList 0 10 
     */  
    @Test  
    public void testGetRList() {  
        RList<Integer> rList=RedisUtils.getInstance().getRList(redisson, "testList");  
        //清除集合  
        rList.clear();  
        Collection<Integer> c=Arrays.asList(12,45,12,34,56,78);  
        rList.addAll(c);  
        //输出结果集  
        System.out.println(Arrays.toString(rList.toArray()));  
    }  

    /** 
     * RQueue 映射为 redis server的list类型 
     * 队列--先入先出 
     *  redis server 命令: 
     * 查看所有键---->keys * 
     * 查看key的类型--->type testQueue 
     * 查看key的值 ---->lrange testQueue 0 10  
     */  
    @Test  
    public void testGetRQueue() {  
        RQueue<Integer> rQueue=RedisUtils.getInstance().getRQueue(redisson, "testQueue");  
        //清除队列  
        rQueue.clear();  
        Collection<Integer> c=Arrays.asList(12,45,12,34,56,78);  
        rQueue.addAll(c);  
        //查看队列元素  
        System.out.println(rQueue.peek());  
        System.out.println(rQueue.element());  
        //移除队列元素  
        System.out.println(rQueue.poll());  
        System.out.println(rQueue.remove());  
        //输出队列  
        System.out.println(Arrays.toString(rQueue.toArray()));  
    }  

    /** 
     * RDeque 映射为 redis server 的 list类型 
     * 双端队列--对头和队尾都可添加或者移除,也遵循队列的先入先出 
     *  redis server 命令: 
     * 查看所有键---->keys * 
     * 查看key的类型--->type testDeque 
     * 查看key的值 ---->lrange testDeque 0 10   
     */  
    @Test  
    public void testGetRDeque() {  
        RDeque<Integer> rDeque=RedisUtils.getInstance().getRDeque(redisson, "testDeque");  
        //清空双端队列  
        rDeque.clear();  
        Collection<Integer> c=Arrays.asList(12,45,12,34,56,78);  
        rDeque.addAll(c);  
        //对头添加元素  
        rDeque.addFirst(100);  
        //队尾添加元素  
        rDeque.addLast(200);  
        System.out.println(Arrays.toString(rDeque.toArray()));  
        //查看对头元素  
        System.out.println(rDeque.peek());  
        System.out.println(rDeque.peekFirst());  
        //查看队尾元素  
        System.out.println(rDeque.peekLast());  
        System.out.println(Arrays.toString(rDeque.toArray()));  
        //移除对头元素  
        System.out.println(rDeque.poll());  
        System.out.println(rDeque.pollFirst());  
        //移除队尾元素  
        System.out.println(rDeque.pollLast());  
        System.out.println(Arrays.toString(rDeque.toArray()));  
        //添加队尾元素  
        System.out.println(rDeque.offer(300));  
        System.out.println(rDeque.offerFirst(400));  
        System.out.println(Arrays.toString(rDeque.toArray()));  
        //移除对头元素  
        System.out.println(rDeque.pop());  
        //显示双端队列的元素  
        System.out.println(Arrays.toString(rDeque.toArray()));  

    }  

    /** 
     * RLock 映射为redis server的string 类型 
     * string中存放 线程标示、线程计数 
     * 查看所有键---->keys * 
     * 查看key的类型--->type testLock1 
     * 查看key的值 ---->get testLock1  
     * 如果想在redis server中 看到 testLock1 
     * 就不能使用   rLock.unlock(); 
     * 因为使用 rLock.unlock(); 之后 就会删除redis server中的 testLock1 
     *  
     */  
    @Test  
    public void testGetRLock() {  
        RLock rLock=RedisUtils.getInstance().getRLock(redisson, "testLock1");  
        if(rLock.isLocked()) rLock.unlock();  
        else rLock.lock();  
        //  
        System.out.println(rLock.getName());  
        System.out.println(rLock.getHoldCount());  
        System.out.println(rLock.isLocked());  
        rLock.unlock();  
    }  

    /** 
     * RAtomicLong 映射为redis server的string 类型 
     * string中数值 
     * 查看所有键---->keys * 
     * 查看key的类型--->type testAtomicLong 
     * 查看key的值 ---->get testAtomicLong  
     */  
    @Test  
    public void testGetRAtomicLong() {  
        RAtomicLong rAtomicLong=RedisUtils.getInstance().getRAtomicLong(redisson, "testAtomicLong");  
        rAtomicLong.set(100);  
        System.out.println(rAtomicLong.addAndGet(200));  
        System.out.println(rAtomicLong.decrementAndGet());  
        System.out.println(rAtomicLong.get());  
    }  

    /** 
     * RCountDownLatch 映射为redis server的string 类型 
     * string中数值 
     * 闭锁--等待其他线程中的操作都做完 在进行操作 
     * 查看所有键---->keys * 
     * 查看key的类型--->type testCountDownLatch 
     * 查看key的值 ---->get testCountDownLatch  
     */  
    @Test  
    public void testGetRCountDownLatch() throws InterruptedException {  
        RCountDownLatch rCountDownLatch=RedisUtils.getInstance().getRCountDownLatch(redisson, "testCountDownLatch");  
        System.out.println(rCountDownLatch.getCount());  
        //rCountDownLatch.trySetCount(1l);  
        System.out.println(rCountDownLatch.getCount());  
        rCountDownLatch.await(10, TimeUnit.SECONDS);  
        System.out.println(rCountDownLatch.getCount());  
    }  

    /** 
     * 消息队列的订阅者 
     * @throws InterruptedException 
     */  
    @Test  
    public void testGetRTopicSub() throws InterruptedException {  
        RTopic<String> rTopic=RedisUtils.getInstance().getRTopic(redisson, "testTopic");  
        rTopic.addListener(new MessageListener<String>() {  

            @Override  
            public void onMessage(String msg) {  
                // TODO Auto-generated method stub  
                System.out.println("你发布的是:"+msg);  
            }  
        });  
        //等待发布者发布消息  
        RCountDownLatch rCountDownLatch=RedisUtils.getInstance().getRCountDownLatch(redisson, "testCountDownLatch");  
        rCountDownLatch.trySetCount(1);  
        rCountDownLatch.await();  
    }  

    /** 
     * 消息队列的发布者 
     */  
    @Test  
    public void testGetRTopicPub() {  
        RTopic<String> rTopic=RedisUtils.getInstance().getRTopic(redisson, "testTopic");  
        System.out.println(rTopic.publish("今天是儿童节,大家儿童节快乐"));  
        //发送完消息后 让订阅者不再等待  
        RCountDownLatch rCountDownLatch=RedisUtils.getInstance().getRCountDownLatch(redisson, "testCountDownLatch");  
        rCountDownLatch.countDown();  
    }  

}  

2.使用jedis操纵数据库

<dependencies>  
  <dependency>  
    <groupId>redis.clients</groupId>  
    <artifactId>jedis</artifactId>  
    <version>2.1.0</version>  
  </dependency>  

  <dependency>  
    <groupId>junit</groupId>  
    <artifactId>junit</artifactId>  
    <version>4.8.2</version>  
    <scope>test</scope>  
  </dependency>  
</dependencies>  
1
2
3
4
5
6
7
8
9
10
11
12
13
14

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.baobaotao.test;

import java.util.ResourceBundle;

import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisPoolTest {

    private static JedisPool jedisPool;  

    /** 
     * initPoolConfig 
     * <br>------------------------------<br> 
     * @return 
     */  
    private static JedisPoolConfig initPoolConfig() {  
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();  
        // 控制一个pool最多有多少个状态为idle的jedis实例  
        jedisPoolConfig.setMaxActive(1000);   
        // 最大能够保持空闲状态的对象数  
        jedisPoolConfig.setMaxIdle(300);  
        // 超时时间  
        jedisPoolConfig.setMaxWait(1000);  
        // 在borrow一个jedis实例时,是否提前进行alidate操作;如果为true,则得到的jedis实例均是可用的;  
        jedisPoolConfig.setTestOnBorrow(true);   
        // 在还会给pool时,是否提前进行validate操作  
        jedisPoolConfig.setTestOnReturn(true);  
        return jedisPoolConfig;  
    }    
    /** 
     * 初始化jedis连接池 
     * <br>------------------------------<br> 
     */  
    @BeforeClass  
    public static void before() {  
        JedisPoolConfig jedisPoolConfig = initPoolConfig();    
        // 属性文件读取参数信息  
        ResourceBundle bundle = ResourceBundle.getBundle("redis");  
        String host = bundle.getString("redis.host");  
        int port = Integer.valueOf(bundle.getString("redis.port"));  
        // 构造连接池  
        jedisPool=new JedisPool(jedisPoolConfig, host, port);
    }  

    @Test  
    public void testSet() {  
        Jedis jedis = null;   
        // 从池中获取一个jedis实例  
        try {  
            jedis = jedisPool.getResource();  
            jedis.set("blog_pool", "java2000_wl");  
        } catch (Exception e) {  
            // 销毁对象  
            jedisPool.returnBrokenResource(jedis);  
            Assert.fail(e.getMessage());  
        } finally {  
            // 还会到连接池  
            jedisPool.returnResource(jedis);  
        }  
    }         
    @Test  
    public void testGet() {  
        Jedis jedis = null;   
        try {  
            // 从池中获取一个jedis实例  
            jedis = jedisPool.getResource();  
            System.out.println(jedis.get("blog_pool"));  
        } catch (Exception e) {  
            // 销毁对象  
            jedisPool.returnBrokenResource(jedis);  
            Assert.fail(e.getMessage());  
        } finally {  
            // 还会到连接池  
            jedisPool.returnResource(jedis);  
        }  
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
尚硅谷是一个教育机构,他们提供了一份关于Redis学习笔记。根据提供的引用内容,我们可以了解到他们提到了一些关于Redis配置和使用的内容。 首先,在引用中提到了通过执行命令"vi /redis-6.2.6/redis.conf"来编辑Redis配置文件。这个命令可以让你进入只读模式来查询"daemonize"配置项的位置。 在引用中提到了Redis会根据键值计算出应该送往的插槽,并且如果不是该客户端对应服务器的插槽,Redis会报错并告知应该前往的Redis实例的地址和端口。 在引用中提到了通过修改Redis的配置文件来指定Redis的日志文件位置。可以使用命令"sudo vim /etc/redis.conf"来编辑Redis的配置文件,并且在文件中指定日志文件的位置。 通过这些引用内容,我们可以得出结论,尚硅谷的Redis学习笔记涵盖了关于Redis的配置和使用的内容,并提供了一些相关的命令和操作示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Redis学习笔记--尚硅谷](https://blog.csdn.net/HHCS231/article/details/123637379)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis学习笔记——尚硅谷](https://blog.csdn.net/qq_48092631/article/details/129662119)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值