zookeeper的javaAPI

一.概述

znode是zookeeper集合的核心组件,zookeeper API提供了一小组方法使用zookeeper集合来操纵znode的所有细节。

客户端应该遵循以下步骤,与zookeeper服务器进行清晰和干净的交互。

  • 连接到zookeeper服务器。zookeeper服务器为客户端分配会话ID。
  • 定期向服务器发送心跳。否则,zookeeper服务器将过期会话ID,客户端需要重新连接。
  • 只要会话ID处于活动状态,就可以获取/设置znode。
  • 所有任务完成后,断开与zookeeper服务器的连接。如果客户端长时间不活动,则zookeeper服务器将自动断开客户端。

二.连接到zookeeper服务器

1.连接zookeeper的语法

Zookeeper(String connectionString,int sessionTimeout,Watcher watcher)
  • connectionString-zookeeper主机
  • sessionTimeout-会话超时(以毫秒为单位)
  • watcher-实现"监视器"对象。zookeeper集合通过监视器对象返回连接状态。

2.演示

(1)代码块

package com.fengmo.zookeeper;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.util.concurrent.CountDownLatch;
public class ZookeeperConnection {
    public static void main(String[] args) {
        try{
            //计数器对象
            CountDownLatch countDownLatch = new CountDownLatch(1);
            //1.创建连接zookeeper服务器对象
            //参数一是zookeeper服务器地址和端口,参数二是连接超时时间,参数三是监视器对象
            ZooKeeper zooKeeper = new ZooKeeper(
                    "192.168.83.134:2181", 5000, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    //2.判断是否创建成功
                    if(event.getState()==Event.KeeperState.SyncConnected){
                        System.out.println("当状态码符合条件,创建成功");
                        countDownLatch.countDown(); //唤醒主线程
                    }
                }
            });
            //主线程阻塞等待连接对象的创建成功
            countDownLatch.await();
            //3.打印会话id
            System.out.println("会话id是" + zooKeeper.getSessionId());
            //4.释放资源
            zooKeeper.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

(2)范例

图片

图片

3.源码

zookeeperDemo01.rar

三.新增节点

1.语法

//同步方式
create(String path,byte[] data,List<ACL> acl,CreateMode createMode)
//异步方式
create(String path,byte[] data,List<ACL> acl,CreateMode createMode,
AsyncCallback.StringCallback callBack,Object ctx)
  • path-znode路径,例如,/node1/node11
  • data-要存储在指定znode路径中的数据。
  • acl-要创建的节点的访问控制列表。zookeeper API提供了一个静态接口ZooDefs.Ids来获取一些基本的acl列表,例如,ZooDefs.Ids.OPEN_ACL_UNSAFE返回打开znode的acl列表。
  • createMode-节点的类型,这是一个枚举。
  • callBack-异步回调接口。
  • ctx-传递上下文参数。

2.演示

(1)全局的建立连接zookeeper服务器方法【准备工作】

(1-1)代码块
@Before
//创建zookeeper的连接
public void before()throws Exception{
    //计数器对象
    CountDownLatch countDownLatch = new CountDownLatch(1);
    //1.创建连接zookeeper服务器对象
    //参数一是zookeeper服务器地址和端口,参数二是连接超时时间,参数三是监视器对象
    zooKeeper = new ZooKeeper(IP, 5000, new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            //2.判断是否创建成功
            if(event.getState()==Event.KeeperState.SyncConnected){
                System.out.println("当状态码符合条件,创建成功");
                countDownLatch.countDown(); //唤醒主线程
            }
        }
    });
    //主线程阻塞等待连接对象的创建成功
    countDownLatch.await();
}
(1-2)范例

图片

图片

(2)全局关闭资源的方法【准备工作】

(2-1)代码块
@After
//释放资源
public void after()throws Exception{
    zooKeeper.close();
}
(2-2)范例

图片

(3)同步创建节点

(3-1)代码块
@Test
//增删改查的节点操作,【同步创建节点】
public void create1()throws Exception{
    zooKeeper.create(
            "/node1/node81",    //节点的路径
            "node1".getBytes(),      //节点的数据
            ZooDefs.Ids.OPEN_ACL_UNSAFE,    //权限列表,world:anyone:cdrwa
            CreateMode.PERSISTENT);     //节点类型:持久化节点
}
(3-2)范例

图片

(4)同步创建节点并设置只读权限

(4-1)代码块
@Test
//增删改查的节点操作,【同步创建节点】【设置只读权限】
public void create2()throws Exception{
    zooKeeper.create(
            "/node1/node82",    //节点的路径
            "node1".getBytes(),      //节点的数据
            ZooDefs.Ids.READ_ACL_UNSAFE,    //权限列表,world:anyone:r  设置只读权限
            CreateMode.PERSISTENT);     //节点类型:持久化节点
}
(4-2)范例

图片

(5)同步创建节点并设置权限列表

(5-1)代码块
@Test
//增删改查的节点操作,【同步创建节点】【设置权限列表】
public void create3()throws Exception{
    //world授权模式
    //1.权限列表
    List<ACL> acls = new ArrayList<ACL>();
    //2.授权模式和授权对象
    Id id = new Id("world","anyone");
    //3.权限设置
    acls.add(new ACL(ZooDefs.Perms.READ,id));   //读权限
    acls.add(new ACL(ZooDefs.Perms.WRITE,id));  //写权限
    //4.创建节点
    zooKeeper.create("/node1/node83","node1".getBytes(),acls,CreateMode.PERSISTENT);
}
(5-2)范例

图片

(6)同步创建节点并ip授权模式

(6-1)代码块
@Test
//增删改查的节点操作,【同步创建节点】【ip授权】
public void create4()throws Exception{
    //ip授权
    //1.权限列表
    List<ACL> acls = new ArrayList<ACL>();
    //2.授权模式和授权对象
    Id id = new Id("ip","192.168.83.134");
    //3.权限设置
    acls.add(new ACL(ZooDefs.Perms.ALL,id));   //所有权限
    //4.创建节点
    zooKeeper.create("/node1/node84","node1".getBytes(),acls,CreateMode.PERSISTENT);
}
(6-2)范例

图片

(7)同步创建节点并auth授权模式

(7-1)代码块
@Test
//增删改查的节点操作,【同步创建节点】【auth授权模式】
public void create5()throws Exception{
    //auth授权模式
    //添加授权用户
    //参数一是授权模式,参数二是用户名和密码,用:分割。
    zooKeeper.addAuthInfo("digest","user2:userpassword2".getBytes());
    //4.创建节点
    zooKeeper.create("/node1/node85","node1".getBytes(),ZooDefs.Ids.CREATOR_ALL_ACL,CreateMode.PERSISTENT);
}
(7-2)范例

图片

(8)同步创建节点并设置指定用户指定节点的访问权限

(8-1)代码块
@Test
//增删改查的节点操作,【同步创建节点】【auth授权模式】【指定认证用户指定节点的访问权限】
public void create6()throws Exception{
    //auth授权模式
    //1.添加授权用户
    //参数一是授权模式,参数二是用户名和密码,用:分割。
    zooKeeper.addAuthInfo("digest","user2:userpassword2".getBytes());
    //2.权限列表
    List<ACL> acls = new ArrayList<ACL>();
    //3.授权模式和授权对象
    Id id = new Id("auth","user2");
    //4.权限设置
    acls.add(new ACL(ZooDefs.Perms.READ,id));   //设置user2用户访问权限为只读
    //5.创建节点
    zooKeeper.create("/node1/node86","node1".getBytes(),acls,CreateMode.PERSISTENT);
}
(8-2)范例

图片

(9)同步创建节点并加密授权模式

(9-1)代码块
//增删改查的节点操作,【同步创建节点】【digest授权模式】
@Test
public void create7()throws Exception{
    //digest模式
    //1.权限列表
    List<ACL> acls = new ArrayList<ACL>();
    //3.授权模式和授权对象
    Id id = new Id("digest","user3:HOzyzzJq3lZmwrnPfLK9voz7DrY=");
    //4.权限设置
    acls.add(new ACL(ZooDefs.Perms.ALL,id));
    //5.创建节点
    zooKeeper.create("/node1/node87","node1".getBytes(),acls,CreateMode.PERSISTENT);
}
(9-2)范例

图片

(10)同步创建节点并设置持久化顺序节点

(10-1)代码块
//增删改查的节点操作,【同步创建节点】【持久化顺序节点】
@Test
public void create8()throws Exception{
    //创建节点   Ids.OPEN_ACL_UNSAFE world:anyone:cdrwa
    String result = zooKeeper.create(
            "/node1/node88",
            "node1".getBytes(),
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.PERSISTENT_SEQUENTIAL);
    //该返回值是该节点路径
    System.out.println(result);
}
(10-2)范例

图片

(11)同步创建节点并设置临时节点

(11-1)代码块
//增删改查的节点操作,【同步创建节点】【临时节点】
@Test
public void create9()throws Exception{
    //创建节点   Ids.OPEN_ACL_UNSAFE world:anyone:cdrwa
    String result = zooKeeper.create(
            "/node1/node89",
            "node1".getBytes(),
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.EPHEMERAL);
    //注意事项:该访问连接资源关闭,则临时节点不存在
    //该返回值是该节点路径
    System.out.println(result);
}
(11-2)范例

图片

(12)同步创建节点并设置临时有序节点

(12-1)代码块
//增删改查的节点操作,【同步创建节点】【临时有序节点】
@Test
public void create10()throws Exception{
    //创建节点   Ids.OPEN_ACL_UNSAFE world:anyone:cdrwa
    String result = zooKeeper.create(
            "/node1/node90",
            "node1".getBytes(),
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.EPHEMERAL_SEQUENTIAL);
    //注意事项:该访问连接资源关闭,则临时节点不存在
    //该返回值是该节点路径
    System.out.println(result);
}
(12-2)范例

图片

(13)异步创建节点

(13-1)代码块
//增删改查的节点操作,【异步请求创建节点】
@Test
public void create11()throws Exception{
    //创建节点   Ids.OPEN_ACL_UNSAFE world:anyone:cdrwa
   zooKeeper.create(
            "/node1/node91", "node1".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL,
           new AsyncCallback.StringCallback() {
               @Override
               public void processResult(int rc, String path, Object ctx, String name) {
                   //0.代表创建成功
                   System.out.println(rc);
                   //节点的路径
                   System.out.println(path);
                   //节点的路径
                   System.out.println(name);
                   //上下文参数,将客户端的ctx("I am context")传给zookeeper服务器
                   System.out.println(ctx);
               }
           },"I am context");
   Thread.sleep(10000);
    System.out.println("结束");
}
(13-2)范例

图片

3.源码

zookeeperDemo01.rar

四.更新节点

1.语法

//同步方式
setData(String path,byte[] data,int version)
//异步方式
setData(String path,byte[] data,int version,AsynCallback.statCallback callBack,Object ctx)
  • path-znode路径。
  • data-要存储在指定znode路径中的数据。
  • version-znode的当前版本。每当数据更改时,Zookeeper会更新znode的版本号。
  • callBack-异步回调接口。
  • ctx-传递上下文参数。

2.演示

(1)连接zookeeper服务器【准备工作】

(1-1)代码块
@Before
//创建zookeeper的连接
public void before()throws Exception{
    //计数器对象
    CountDownLatch countDownLatch = new CountDownLatch(1);
    //1.创建连接zookeeper服务器对象
    //参数一是zookeeper服务器地址和端口,参数二是连接超时时间,参数三是监视器对象
    zooKeeper = new ZooKeeper(IP, 5000, new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            //2.判断是否创建成功
            if(event.getState()==Event.KeeperState.SyncConnected){
                System.out.println("当状态码符合条件,创建成功");
                countDownLatch.countDown(); //唤醒主线程
            }
        }
    });
    //主线程阻塞等待连接对象的创建成功
    countDownLatch.await();
}
(1-2)范例

图片

(2)关闭资源【准备工作】

(2-1)代码块
@After
//释放资源
public void after()throws Exception{
    zooKeeper.close();
}
(2-2)范例

图片

(3)同步修改节点数据【不更新节点版本号】

(3-1)代码块
@Test
//不修改版本的修改指定节点的数据【同步】
public void set1()throws Exception{
    //参数一:节点的路径,参数二:修改的数据,参数三:数据版本号。-1代表版本号不参与更新
    zooKeeper.setData("/node2/node21","node111".getBytes(),-1);
}
(3-2)范例

图片

(4)同步修改节点数据【更新节点版本号】

(4-1)代码块
@Test
//修改指定版本的指定节点的数据【同步】
public void set2()throws Exception{
    /*
        cZxid = 0x87
        ctime = Thu Jan 21 09:11:06 CST 2021
        mZxid = 0x8a
        mtime = Thu Jan 21 09:17:01 CST 2021
        pZxid = 0x87
        cversion = 0
        dataVersion = 1
        aclVersion = 0
        ephemeralOwner = 0x0
        dataLength = 7
        numChildren = 0
     */
    //参数一:节点的路径,参数二:修改的数据,参数三:数据版本号。
    zooKeeper.setData("/node2/node21","node222".getBytes(),1);  //需要dataVersion一致
}
(4-2)范例

图片

(5)异步请求修改节点数据

(5-1)代码块
@Test
//修改版本的节点数据【异步】
public void test3()throws Exception{
    zooKeeper.setData("/node2/node22","node224".getBytes(),-1, new AsyncCallback.StatCallback() {
        @Override
        public void processResult(int rc, String path, Object ctx, Stat stat) {
            // 0代表修改成功
            System.out.println(rc);
            //节点的路径:path
            System.out.println(path);
            //上下文参数对象:ctx
            System.out.println(ctx);
            //属性描述对象:stat
            System.out.println(stat.getVersion());  //获取版本号
        }
    },"I am Context!!!");
    Thread.sleep(1000);
    System.out.println("结束");
}
(5-2)范例

图片

五.删除节点

1.语法

//同步方式
delete(String path,int version)
//异步请求
detlet(String path,int version,AsyncCallback.VoidCallback callBack,Object ctx)

path-znode路径。
version-znode的当前版本。

callback-异步回调接口

ctx-传递上下文参数

2.演示

(1)连接zookeeper服务器【准备工作】

(1-1)代码块
@Before
//创建zookeeper的连接
public void before()throws Exception{
    //计数器对象
    CountDownLatch countDownLatch = new CountDownLatch(1);
    //1.创建连接zookeeper服务器对象
    //参数一是zookeeper服务器地址和端口,参数二是连接超时时间,参数三是监视器对象
    zooKeeper = new ZooKeeper(IP, 5000, new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            //2.判断是否创建成功
            if(event.getState()==Event.KeeperState.SyncConnected){
                System.out.println("当状态码符合条件,创建成功");
                countDownLatch.countDown(); //唤醒主线程
            }
        }
    });
    //主线程阻塞等待连接对象的创建成功
    countDownLatch.await();
}
(1-2)范例

图片

(2)关闭资源【准备工作】

(2-1)代码块
@After
//释放资源
public void after()throws Exception{
    zooKeeper.close();
}
(2-2)范例

图片

(3)同步删除节点【不考虑版本号】

(3-1)代码块
@Test
//删除节点,但不考虑版本号。【同步】
public void delete1()throws Exception{
    //参数一:节点的路径,参数二:数据版本号。-1代表版本号不参与更新
    zooKeeper.delete("/delznode/node1",-1);
}
(3-2)范例

图片

(4)同步删除节点【设置版本号】

(4-1)代码块
@Test
//删除节点,但指定版本。【同步】
public void delete2()throws Exception{
    //参数一:节点的路径,参数二:数据版本号。-1代表版本号不参与更新
    zooKeeper.delete("/delznode/node2",2);
}
(4-2)范例

图片

(5)异步删除节点【不考虑版本号】

(5-1)代码块
@Test
//删除节点,但不考虑版本号。【异步】
public void delete3()throws Exception{
    //参数一:节点的路径,参数二:数据版本号。-1代表版本号不参与更新
    zooKeeper.delete("/delznode/node2", -1, new AsyncCallback.VoidCallback() {
        @Override
        public void processResult(int rc, String path, Object ctx) {
            //0是删除成功
            System.out.println(rc);
            //节点路径 path
            System.out.println(path);
            //上下文参数传递ctx
            System.out.println(ctx);
        }
    },"I am context!!!");
    Thread.sleep(1000);
    System.out.println("结束");
}
(5-2)范例

图片

六.查看节点

1.语法

//同步方式
getData(String path,boolean b,Stat stat)
//异步方式
getData(String path,boolean b,AsyncCallback.DataCallback callBack,Object ctx)

path-znode路径。

b-是否使用连接对象中注册的监听器。

stat-返回znode的元数据。

callBack-异步回调接口。

ctx-传递上下文参数。

2.演示

(1)连接zookeeper服务器【准备工作】

(1-1)代码块
@Before
//创建zookeeper的连接
public void before()throws Exception{
    //计数器对象
    CountDownLatch countDownLatch = new CountDownLatch(1);
    //1.创建连接zookeeper服务器对象
    //参数一是zookeeper服务器地址和端口,参数二是连接超时时间,参数三是监视器对象
    zooKeeper = new ZooKeeper(IP, 5000, new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            //2.判断是否创建成功
            if(event.getState()==Event.KeeperState.SyncConnected){
                System.out.println("当状态码符合条件,创建成功");
                countDownLatch.countDown(); //唤醒主线程
            }
        }
    });
    //主线程阻塞等待连接对象的创建成功
    countDownLatch.await();
}
(1-2)范例

图片

(2)关闭资源【准备工作】

(2-1)代码块
@After
//释放资源
public void after()throws Exception{
    zooKeeper.close();
}
(2-2)范例

图片

(3)获取数据【同步】

(3-1)代码块
@Test
//获取数据【同步】
public void get1()throws Exception{
    //参数一:节点路径。参数二:监听器,参数三:读取节点属性的对象
    Stat stat = new Stat(); //创建节点信息对象
    byte[] bys = zooKeeper.getData("/getnode/node1", false, stat);
    //打印数据
    System.out.println(new String(bys));
}
(3-2)范例

图片

(4)获取数据【异步】

(4-1)代码块
//获取数据【异步】
@Test
public void get2()throws Exception{
    //参数一:节点路径。参数二:监听器,参数三:读取节点属性
    zooKeeper.getData("/getnode/node1", false, new AsyncCallback.DataCallback() {
        @Override
        public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {
            //0代表读取成功
            System.out.println(rc);
            //节点路径
            System.out.println(path);
            //上下文参数对象
            System.out.println(ctx);
            //数据
            System.out.println(new String(data));
            //属性对象
            System.out.println(stat.getVersion());
        }
    },"I am context");
    Thread.sleep(10000);
    System.out.println("结束");
}
(4-2)范例

图片

七.查看子节点

1.语法

//同步方式
getChildren(String path,boolean b)
//异步方式
getChildren(String path,boolean b,AsyncCallback.childrenCallback callBack,Object ctx)
  • path-Znode路径。
  • b-是否使用连接对象中注册的监视器。
  • callBack-异步回调接口。
  • ctx-传递上下文参数。

2.演示

(1)连接zookeeper服务器【准备工作】

(1-1)代码块
@Before
//创建zookeeper的连接
public void before()throws Exception{
    //计数器对象
    CountDownLatch countDownLatch = new CountDownLatch(1);
    //1.创建连接zookeeper服务器对象
    //参数一是zookeeper服务器地址和端口,参数二是连接超时时间,参数三是监视器对象
    zooKeeper = new ZooKeeper(IP, 5000, new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            //2.判断是否创建成功
            if(event.getState()==Event.KeeperState.SyncConnected){
                System.out.println("当状态码符合条件,创建成功");
                countDownLatch.countDown(); //唤醒主线程
            }
        }
    });
    //主线程阻塞等待连接对象的创建成功
    countDownLatch.await();
}
(1-2)范例

图片

(2)关闭资源【准备工作】

(2-1)代码块
@After
//释放资源
public void after()throws Exception{
    zooKeeper.close();
}
(2-2)范例

图片

(3)获取数据【同步】

(3-1)代码块
@Test
//获取子节点【同步】
public void child1()throws Exception{
    //参数一:子节点的父路径,参数二:监听器
    List<String> list = zooKeeper.getChildren("/getchild",false);
    for(String str : list){
        System.out.println(str);
    }
}
(3-2)范例

图片

(4)获取数据【异步】

(4-1)代码块
@Test
//获取子节点【异步】
public void child2()throws Exception{
    //参数一:子节点的父路径,参数二:监听器
    zooKeeper.getChildren("/getchild", false, new AsyncCallback.ChildrenCallback() {
        @Override
        public void processResult(int rc, String path, Object ctx, List<String> children) {
            // 0代表读取成功
            System.out.println(rc);
            //节点的路径
            System.out.println(path);
            //上下文参数对象
            System.out.println(ctx);
            //子节点信息
            for (String str: children) {
                System.out.println(str);
            }
        }
    },"I am Context");
    Thread.sleep(10000);
    System.out.println("结束");
}
(4-2)范例

图片

八.检查节点是否存在

1.语法

//同步方法
exits(String path,boolean b)
//异步方法
exits(String path,boolean b,AsyncCallback.StatCallback callBack,Object ctx)

path-znode路径。
b-是否使用连接对象中注册的监视器。

callBack-异步回调接口。

ctx-传递上下文参数。

2.演示

(1)连接zookeeper服务器【准备工作】

(1-1)代码块
@Before
//创建zookeeper的连接
public void before()throws Exception{
    //计数器对象
    CountDownLatch countDownLatch = new CountDownLatch(1);
    //1.创建连接zookeeper服务器对象
    //参数一是zookeeper服务器地址和端口,参数二是连接超时时间,参数三是监视器对象
    zooKeeper = new ZooKeeper(IP, 5000, new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            //2.判断是否创建成功
            if(event.getState()==Event.KeeperState.SyncConnected){
                System.out.println("当状态码符合条件,创建成功");
                countDownLatch.countDown(); //唤醒主线程
            }
        }
    });
    //主线程阻塞等待连接对象的创建成功
    countDownLatch.await();
}
(1-2)范例

图片

(2)关闭资源【准备工作】

(2-1)代码块
@After
//释放资源
public void after()throws Exception{
    zooKeeper.close();
}
(2-2)范例

图片

(3)同步查询节点是否存在

(3-1)代码块
@Test
public void exists1()throws Exception{
    //参数一:节点路径。参数二:监视器。
    Stat stat = zooKeeper.exists("/node1", false);
    System.out.println(stat);   //读取节点的状态信息,
}
(3-2)范例

图片

(4)异步查询节点是否存在

(4-1)代码块
@Test
//异步查看节点是否存在
public void exists2()throws Exception{
    //参数一:节点路径。参数二:监视器。
   zooKeeper.exists("/node1", false, new AsyncCallback.StatCallback() {
        @Override
        public void processResult(int rc, String path, Object ctx, Stat stat) {
            //0表示方法执行成功
            System.out.println(rc);
            //节点的路径
            System.out.println(path);
            //上下文参数
            System.out.println(ctx);
            //节点的版本信息
            System.out.println(stat.getVersion());
        }
    },"I am context");
}
(4-2)范例

图片

九.源码

zookeeperDemo01.rar

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值