Redis的分布式锁

redis的分布式锁的实现+缓存

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

RedisDistributeLock 定义了一些分布式锁的接口 实现, 本人能力有限,只实现了 非公平锁

package org.study.distributed_look.redis.way2;

import redis.clients.jedis.Jedis;

/**
 * @Author: huangwenjun
 * @Description:
 * @Date: Created in 13:45  2018/5/22
 **/
public interface RedisDistributeLock {

    /**
     * 公平锁, 只能说 本机的公平
     * @param jedis
     * @param key
     * @param uuid
     */
    void fairLock(Jedis jedis, String key, String uuid);

    /**
     * 非公平锁
     * @param jedis
     * @param key
     * @param uuid
     */
    void unfairLock(Jedis jedis, String key, String uuid);

    /**
     * 锁 默认非公平
     * @param jedis
     * @param key
     * @param uuid
     */
    void lock(Jedis jedis, String key, String uuid);

    /**
     * 解锁
     * @param jedis
     * @param key
     * @param uuid
     */
    void release(Jedis jedis, String key, String uuid);
}

------------DefaultRedisDistributeLock 是我封装的 默认的分布式锁的实现--------------------------

package org.study.distributed_look.redis.way2;

import org.study.distributed_look.redis.RedisTool;
import redis.clients.jedis.Jedis;


public class DefaultRedisDistributeLock implements RedisDistributeLock {

   
    private static final Boolean DEFALUT_FAIR = false; // 默认非公平锁

   
    private static final Integer DEFAULT_EXPIRE_TIME = 10000; //设置过期时间是10S

    private Boolean isFair;  

    private Integer expireTime;

    public DefaultRedisDistributeLock() {
        isFair = DEFALUT_FAIR;
        expireTime = DEFAULT_EXPIRE_TIME;
    }   //为两个属性赋予默认值, 通过构造方法

    public DefaultRedisDistributeLock(boolean isFair, Integer expireTime) {
        isFair = isFair;
        expireTime = expireTime;
    } // 也可以认为的自定义锁是公平还是非公平的, 以及超时时间

    @Override   //覆盖上锁方法
    public void lock(Jedis jedis, String key, String uuid) {
        if (isFair) {  //公平锁调用 公共锁方法 
            fairLock(jedis, key, uuid);
        } else {
            unfairLock(jedis, key, uuid);
        }
    }

    @Override  //公平锁的方法
    public void fairLock(Jedis jedis, String key, String uuid) {
        // 通过一个队列维护, 参照 AQS 实现
    }

    @Override  //释放
    public void release(Jedis jedis, String key, String uuid) {
        try {
            while (true) {
                boolean released = RedisTool.releaseDistributedLock(jedis, key, uuid);

                if (released) {
                    break;
                }
            }
        } finally {
            jedis.close();
        }
    }

    @Override  //非公平锁的实现
    public void unfairLock(Jedis jedis, String key, String uuid) {
        while (true) { //死循环获取
        //通过分装的redid的工具类的尝试获取锁来实现
            boolean locked = RedisTool.tryGetDistributedLock(jedis, key, uuid, expireTime);
      
            if (locked) {  
                break;  //如果获取锁 就跳出循环。
            }
        }
    }
}

---------------------正确的实现了 redis 分布式锁的 获取 和 释放----------------------

package org.study.distributed_look.redis;

import redis.clients.jedis.Jedis;

import java.util.Collections;

public class RedisTool {

    private static final String LOCK_SUCCESS = "OK";   //获取锁成功的标志
    private static final String SET_IF_NOT_EXIST = "NX";  //锁的key
    private static final String SET_WITH_EXPIRE_TIME = "PX"; //  请求标识

    private static final Long RELEASE_SUCCESS = 1L;

    /**
     * 尝试获取分布式锁
     *
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }

        return false;
    }

    /**
     * 释放分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }

        return false;
    }
}
-----------------------------------

package org.study.distributed_look.redis.way2;

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

/**
 * @Author: huangwenjun
 * @Description:
 * @Date: Created in 14:10  2018/5/22
 **/
public class TestRedisDistributeLock {

    public static void main(String[] args) {
        for (int i = 1; i < 10; i ++) {
            new TestLock().start();
        }
    }

    static class TestLock extends Thread {

        static RedisDistributeLock locker = new DefaultRedisDistributeLock();

        JedisPool jedisPool = new JedisPool();

        @Override
        public void run() {
            Jedis jedis = jedisPool.getResource();
            locker.lock(jedis, "test1", "qwerqwer");

            // TODO 模拟业务
            System.out.println(Thread.currentThread().getName() + " get lock.....");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " release lock.....");

            locker.release(jedis, "test1", "qwerqwer");
        }
    }
}
--------------测试结果----------------------

hread-4 get lock.....
Thread-4 release lock.....
Thread-2 get lock.....
Thread-2 release lock.....
Thread-7 get lock.....
Thread-7 release lock.....
Thread-9 get lock.....
Thread-9 release lock.....
Thread-0 get lock.....
Thread-0 release lock.....
Thread-8 get lock.....
Thread-8 release lock.....
Thread-5 get lock.....
Thread-5 release lock.....
Thread-6 get lock.....
Thread-6 release lock.....
Thread-3 get lock.....
Thread-3 release lock.....

Redis的缓存

启动redis

[root@SparkOnStandalone redis-4.0.10]# cd /usr/redis/bin/
[root@SparkOnStandalone bin]# ./redis-server

7.新开一个窗口使用客户端操作

[root@SparkOnStandalone ~]# cd /usr/redis/bin/
[root@SparkOnStandalone bin]# ./redis-cli

1.在Springboot 启动程序中添加@EnableCaching 注解开启缓存
2.配置缓存 application .yml中添加缓存的配置

Redis的安装

  1. 准备vmware虚拟机一台

  2. 上传redis压缩包

  3. 执行 tar -zxvf redis压缩包 解压过后是redis的源码包

  4. 执行 yum -y install gcc 因为redis是c语言编写 需要下载初始化编译环境 gcc

  5. 执行 make MALLOC=libc 编译redis源码包

  6. 执行 make install PREFIX=/usr/redis 编译完成后指定位置安装redis

  7. 进入 redis的bin目录 执行 ./redis-srver 开启redis

  8. 执行 ./redis-cli -p 6379 连接redis

  9. 执行 ./redis-cli 登陆

  10. 设置redis密码

    127.0.0.1:6379> config set requirepass 123
    OK
    127.0.0.1:6379> ahuth 123
    (error) ERR unknown command ‘ahuth’
    127.0.0.1:6379> auth 123
    OK
    127.0.0.1:6379>

Spring Data提供了很多的模块去支持各种数据库的操作。

Spring Data主要使用的一些模块,根据需要选择对应的一些功能模块。

Spring Data common- 支持每个Spring Data模块的Core Spring概念。
Spring Data JDBC- 对JDBC的Spring Data存储库支持。
Spring Data JPA - 对JPA的Spring Data存储库支持。
Spring Data MongoDB - 对MongoDB的基于Spring对象文档的存储库支持。
Spring Data Redis - 从Spring应用程序轻松配置和访问Redis。
Spring Data JDBC Ext- 支持标准JDBC的数据库特定扩展,包括对Oracle RAC快速连接故障转移的支持,AQ JMS支持以及对使用高级数据类型的支持。
Spring Data KeyValue - Map基于库和SPI轻松建立键值存储一个Spring数据模块。
Spring Data LDAP - 对Spring LDAP的 Spring Data存储库支持。
Spring Data REST- 将Spring Data存储库导出为超媒体驱动的RESTful资源。
Spring Data for Pivotal GemFire - 轻松配置和访问Pivotal GemFire,实现高度一致,低延迟/高吞吐量,面向数据的Spring应用程序。
Spring Data for Apache Cassandra- 轻松配置和访问Apache Cassandra或大规模,高可用性,面向数据的Spring应用程序。
Spring Data for Apace Geode- 轻松配置和访问Apache Geode,实现高度一致,低延迟,面向数据的Spring应用程序。
Spring Data for Apache Solr- 为面向搜索的Spring应用程序轻松配置和访问Apache Solr。
在这里插入图片描述

缓存中的key的设计
一般的redsi的key的设计 :类名+方法名+实参
在这里插入图片描述
目录结构

在这里插入图片描述
yml配置文件

server:
  port: 9999
  context-path: /MyLog
  jsp-servlet:
    init-parameters:
      development: true


spring:
  mvc:
    view:
      suffix: .jsp
      prefix: /
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/hadoop
    #url: jdbc:mysql://localhost:3306/test #验证mysql树状查询
    driver-class-name: com.mysql.jdbc.Driver
  #cache:
    #type: redis  #使用的缓存的类型是redis二级外置缓存
  redis: #redis的设置
    database: 1 #表示使用0号数据库
    host: 192.168.23.201
    port: 7000 #端口号
  #set spring.freemarker.checkTemplateLocation=false
  freemarker:
    check-template-location: false
mybatis:
  type-aliases-package: com.baizhi.entity
  mapper-locations: classpath:com/baizhi/dao/*Mapper.xml

service下的接口

普通的查询实现即可

public interface MessageService {
    //查询所有
    public List<Map<String,Object>> selectAll();
    //查询所有状态
    public List<Map<String,Object>> selectStatus(String createtime);
    //---------通过时间查询独立用户访问量
    public List<List<Object>> selectUser(String time);
    //查询所有病例
    public List<List<Object>> selectMassage();

}


dao接口

public interface IntoDb {
   

    //---------------查询所有的病例----------
    public List<Massage> selectallMassage();
}

xml配置文件
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.baizhi.dao.IntoDb">
    <insert id="insert">
      insert into get (time,sum) values (#{time},#{sum});
  </insert>

    <!-- 查询所有的数据 -->

    <select id="selectMessage" resultType="Into">
        select time ,sum from get ;
    </select>
<select id="selectallMassage" resultType="Massage">
         select time ,definitecasenum,suspectednum,curenum,didenum,definitecasenum+suspectednum as sum ,definitecasenum-curenum-didenum as corentdefinitecasenum
from t_sta;
    </select>

</mapper>

cache下的缓存实现

package com.baizhi.cache;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import javax.annotation.Resource;

@Configuration //配置文件
@Aspect //表示切面
public class RediaCache {

    @Resource
    private RedisTemplate redisTemplate;

    //环绕通知
    @Around("execution(* com.baizhi.service.*.select*(..))")
    //给server包下面的所有的select添加该方法
    //封装了原始类的方法,结果
    public Object around(ProceedingJoinPoint proceedingJoinPoint){

        System.out.println("环绕通知----->");
        //解决缓存的key乱码问题
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);


        StringBuilder sb = new StringBuilder();
        //设计一个key(类名+方法名+实参) value (查询的结果)

        //获取类的权限定名
        String clazzname = proceedingJoinPoint.getTarget().getClass().getName();
        //获取方法名                               //Signature签名的意思
        String methodNmae = proceedingJoinPoint.getSignature().getName();
        sb.append(clazzname).append(methodNmae);
        //获取实参
        Object[] args = proceedingJoinPoint.getArgs();
        for (Object arg : args) {
            sb.append(arg);
        }

        String key = sb.toString();//设计存放入redis的key
        //String类型的操作
        ValueOperations valueOperations = redisTemplate.opsForValue();

        Object result =null;//声明传的结果
        //判断缓存中是否存在
        if (redisTemplate.hasKey(key)){ //存在true
            //查询redis返回结果
             result = valueOperations.get(key);
            System.out.println("查询缓存:"+result);

        }else {

            try {
                //获取结果的时候可能存在异常proceed();
               result = proceedingJoinPoint.proceed();
                valueOperations.set(key,result);//将查询到的数据存入缓存中

                System.out.println("查询mysql:"+result);
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }

            //不存在将mysql查询的结果放入
        }
        return result;
    }

}


清除缓存


/*
 * 清空缓存
* */
 @Resource   //它是redisTemplate的子类
    private StringRedisTemplate stringRedisTemplate;//专门操作String类型的

@After("execution(* com.baizhi.service.*.*(..)) && !execution(* com.baizhi.service.*.select*(..)) ")
public void after(JoinPoint joinPoint){

    System.out.println("==清空缓存==");
    //类的全限定名
    String className = joinPoint.getTarget().getClass().getName();

    //获取所有的key
    Set<String> keys = stringRedisTemplate.keys("*");  //相当于keys *命令操作。获取所有的 key
    //遍历所有的key
    for (String key : keys) {

        //判断符合条件的key
        if(key.startsWith(className)){
            //清除
            stringRedisTemplate.delete(key);
        }
    }
}

测试
http://localhost:9999//MyLog/view/sta.html
访问controller方法
http://localhost:9999//MyLog/log/showMassage

结果展示

环绕通知----->
查询mysql:[[2019-01-22, 2019-01-23, 2019-01-24, 2019-01-25, 2019-01-26, 2019-01-27, 2019-01-28, 2019-01-29, 2019-01-30, 2019-01-31, 
环绕通知----->
查询缓存:[[2019-01-22, 2019-01-23, 2019-01-24, 2019-01-25, 2019-01-26, 2019-01-27, 2019-01-28, 2019-01-29, 2019-01-30, 2019-01-31, 
环绕通知----->
查询缓存:[[2019-01-22, 2019-01-23, 2019-01-24, 2019-01-25, 2019-01-26, 2019-01-27, 2019-01-28, 2019-01-29, 2019-01-30, 2019-01-31, 2
package com.baizhi.test;

import com.baizhi.Application;
import com.baizhi.dao.IntoDb;
import com.baizhi.entity.Node;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class t1 {

    //对redia数据库的操作
    @Resource
    private RedisTemplate redisTemplate;

    @Resource   //它是redisTemplate的子类
    private StringRedisTemplate stringRedisTemplate;//专门操作String类型的

    @Autowired
    private IntoDb intoDb;

    @Test
    public  void  test1(){

        List<Node> nodeTree = intoDb.getNodeTree();
        for (Node node : nodeTree) {
            System.out.println(node);
        }
    }

    //写入redis
    @Test
    public  void  testRedis(){
        //对String类型的操作
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("age","123");

    }
    //读取redis的数据
    @Test
    public  void  readRedis1(){
        //对String类型的操作
        ValueOperations valueOperations = redisTemplate.opsForValue();
        Object age = valueOperations.get("age");
        System.out.println("结果是:"+age);  //123

        Set<String> keys = stringRedisTemplate.keys("*");
        for (String key : keys) {
            System.out.println("------>"+key);
        }

    }




}


pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.baizhi</groupId>
  <artifactId>Statistical</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>Statistical Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <!--继承springboot的父项目-->
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.7.RELEASE</version>
  </parent>




  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.1.1</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.38</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>org.junit.vintage</groupId>
          <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
      </exclusions>
    </dependency>


    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-hdfs -->
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-hdfs</artifactId>
      <version>2.6.0</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-common</artifactId>
      <version>2.6.0</version>
    </dependency>

    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-mapreduce-client-core</artifactId>
      <version>2.6.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
      <version>2.6.0</version>
    </dependency>

    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-mapreduce-client-common</artifactId>
      <version>2.6.0</version>
    </dependency>

    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-client</artifactId>
      <version>1.2.4</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-common</artifactId>
      <version>1.2.4</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-protocol</artifactId>
      <version>1.2.4</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-server</artifactId>
      <version>1.2.4</version>
    </dependency>
    <!-- springboot与email的整合 -->

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.8.1</version>
    </dependency>



    <!--springData操作redis-->
    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
      <version>2.1.3.RELEASE</version>
    </dependency>


    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>2.9.0</version>
    </dependency>





    <!--aop-->
    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
      <version>2.2.5.RELEASE</version>
    </dependency>

  </dependencies>

  <build>
    <finalName>Statistical</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>

    </pluginManagement>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>8</source>
          <target>8</target>
        </configuration>
      </plugin>


      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>

    </plugins>

  </build>
</project>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值