HBase客户端SQL引擎之Apache Phoenix的安装与使用

HBase客户端SQL引擎之Apache Phoenix的安装与使用

Apache Phoenix为Apache Hadoop 提供基于SQL的OLTP和运营分析,使用Apache HBase作为其后备存储,并提供与Apache生态系统中其他项目的集成,如Spark、Hive、Pig、Flume和MapReduce ......

目录

HBase客户端SQL引擎之Apache Phoenix的安装与使用

1 概述

2 部署apache-phoenix-5.0.0-HBase-2.0

3 SQL基本操作

4 使用hbase shell创建表student

5 表映射-映射已有的HBase表

6 视图映射-映射已有的HBase表

7 通过DBeaver连接Phoenix操作HBase

7.1 下载及安装

7.2 启动及准备驱动包

7.3 创建数据库连接 

7.4 操作指引 

系列文章


 


1 概述


  • Phoenix最早是saleforce的一个开源项目,后来成为Apache基金的顶级项目。
  • Phoenix是构建在HBase上的一个SQL层,能让我们用标准的JDBC APIs而不是HBase客户端APIs来创建表、插入数据和对HBase数据进行查询。
  • Phoenix完全使用Java编写,作为HBase内嵌的JDBC驱动。Phoenix查询引擎会将SQL查询转换为一个或多个HBase扫描,并编排执行以生成标准的JDBC结果集。
  • 直接使用HBase API、协同处理器与自定义过滤器,对于简单查询来说,其性能量级是毫秒,对于百万级别的行数来说,其性能量级是秒。
  • 下载的Phoenix版本必须和hbase目标版本保持一致。

2 部署apache-phoenix-5.0.0-HBase-2.0

  • 下载及解压 (hd100上执行)

[root@hd100 ~]# cd /opt/src/
[root@hd100 src]# wget https://mirrors.tuna.tsinghua.edu.cn/apache/phoenix/apache-phoenix-5.0.0-HBase-2.0/bin/apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz
...
[root@hd100 src]# ls -l apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz
-rw-r--r-- 1 root root 436868323 11月 12 14:47 apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz
[root@hd100 src]# tar -zxvf apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz
...
[root@hd100 src]# mv apache-phoenix-5.0.0-HBase-2.0-bin /home/hadoop/phoenix-5.0.0-HBase-2.0
[root@hd100 src]# cd /home/hadoop/phoenix-5.0.0-HBase-2.0
  • vi /home/hadoop/hbase/conf/hbase-site.xml #增加以下内容

  <property>
    <name>phoenix.schema.isNamespaceMappingEnabled</name>
    <value>true</value>
  </property>
  <property>
    <name>phoenix.schema.mapSystemTablesToNamespace</name>
    <value>true</value>
  </property>
  • 拷贝hbase和hadoop配置文件到phoenix (hd100上执行)

[root@hd100 phoenix-5.0.0-HBase-2.0]# ls /home/hadoop/hbase/conf/hbase-site.xml /home/hadoop/hadoop/etc/hadoop/{core-site.xml,hdfs-site.xml}
/home/hadoop/hadoop/etc/hadoop/core-site.xml  /home/hadoop/hadoop/etc/hadoop/hdfs-site.xml  /home/hadoop/hbase/conf/hbase-site.xml
[root@hd100 phoenix-5.0.0-HBase-2.0]# cp /home/hadoop/hbase/conf/hbase-site.xml /home/hadoop/hadoop/etc/hadoop/{core-site.xml,hdfs-site.xml} /home/hadoop/phoenix-5.0.0-HBase-2.0/bin/
  • 拷贝phoenix到其他节点 (hd100上执行)

[root@hd100 phoenix-5.0.0-HBase-2.0]# scp -r /home/hadoop/phoenix-5.0.0-HBase-2.0 hd110:/home/hadoop/
[root@hd100 phoenix-5.0.0-HBase-2.0]# scp -r /home/hadoop/phoenix-5.0.0-HBase-2.0 hd120:/home/hadoop/
  • 拷贝phoenix的jar包到hbase中 (hd100上执行)(/home/hadoop/phoenix-5.0.0-HBase-2.0目录下)

[root@hd100 phoenix-5.0.0-HBase-2.0]# pwd
/home/hadoop/phoenix-5.0.0-HBase-2.0
[root@hd100 phoenix-5.0.0-HBase-2.0]# ls -l phoenix-5.0.0-HBase-2.0-server.jar phoenix-core-5.0.0-HBase-2.0.jar phoenix-5.0.0-HBase-2.0-client.jar
-rw-r--r-- 1 502 games 135109092 6月  27 2018 phoenix-5.0.0-HBase-2.0-client.jar
-rw-r--r-- 1 502 games  41800313 6月  27 2018 phoenix-5.0.0-HBase-2.0-server.jar
-rw-r--r-- 1 502 games   4317285 6月  27 2018 phoenix-core-5.0.0-HBase-2.0.jar
[root@hd100 phoenix-5.0.0-HBase-2.0]# scp phoenix-5.0.0-HBase-2.0-server.jar phoenix-core-5.0.0-HBase-2.0.jar phoenix-5.0.0-HBase-2.0-client.jar hd100:/home/hadoop/hbase/lib/
[root@hd100 phoenix-5.0.0-HBase-2.0]# scp phoenix-5.0.0-HBase-2.0-server.jar phoenix-core-5.0.0-HBase-2.0.jar phoenix-5.0.0-HBase-2.0-client.jar hd110:/home/hadoop/hbase/lib/
[root@hd100 phoenix-5.0.0-HBase-2.0]# scp phoenix-5.0.0-HBase-2.0-server.jar phoenix-core-5.0.0-HBase-2.0.jar phoenix-5.0.0-HBase-2.0-client.jar hd120:/home/hadoop/hbase/lib/
  • 重启hbase

  • 运行phoenix

    /home/hadoop/phoenix-5.0.0-HBase-2.0目录下

[root@hd100 phoenix-5.0.0-HBase-2.0]# pwd
/home/hadoop/phoenix-5.0.0-HBase-2.0

首次启动会在hbase中自动生成5张表,在phoenix中也可以看到

[root@hd100 phoenix-5.0.0-HBase-2.0]# bin/sqlline.py
Setting property: [incremental, false]
Setting property: [isolation, TRANSACTION_READ_COMMITTED]
issuing: !connect jdbc:phoenix: none none org.apache.phoenix.jdbc.PhoenixDriver
Connecting to jdbc:phoenix:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/home/hadoop/phoenix-5.0.0-HBase-2.0/phoenix-5.0.0-HBase-2.0-client.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/home/hadoop/hadoop/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
20/11/14 21:57:05 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Connected to: Phoenix (version 5.0)
Driver: PhoenixEmbeddedDriver (version 5.0)
Autocommit status: true
Transaction isolation: TRANSACTION_READ_COMMITTED
Building list of tables and columns for tab-completion (set fastconnect to true to skip)...
133/133 (100%) Done
Done
sqlline version 1.2.0
0: jdbc:phoenix:> !tables
+------------+--------------+-------------+---------------+----------+------------+----------------------------+-----------------+--------------+---+
| TABLE_CAT  | TABLE_SCHEM  | TABLE_NAME  |  TABLE_TYPE   | REMARKS  | TYPE_NAME  | SELF_REFERENCING_COL_NAME  | REF_GENERATION  | INDEX_STATE  | I |
+------------+--------------+-------------+---------------+----------+------------+----------------------------+-----------------+--------------+---+
|            | SYSTEM       | CATALOG     | SYSTEM TABLE  |          |            |                            |                 |              | f |
|            | SYSTEM       | FUNCTION    | SYSTEM TABLE  |          |            |                            |                 |              | f |
|            | SYSTEM       | LOG         | SYSTEM TABLE  |          |            |                            |                 |              | t |
|            | SYSTEM       | SEQUENCE    | SYSTEM TABLE  |          |            |                            |                 |              | f |
|            | SYSTEM       | STATS       | SYSTEM TABLE  |          |            |                            |                 |              | f |
+------------+--------------+-------------+---------------+----------+------------+----------------------------+-----------------+--------------+---+
0: jdbc:phoenix:>

3 SQL基本操作

  • 说明

  1. Phoenix 对表名和列名都是区分大小写的,但是,如果不加双引号,则默认为大写。

  2. 表名要和 HBase 中建立的表名一致。HBase 默认的主列名是 ROW,所以要将“ROW”设置为主键。列簇和列名也要用双引号括起来,要不然小写会自动变成大写。

  3. 删除映射表,会同时删除原有HBase表。 4.10之后的phoenix版本不能先创建表映射,再创建视图映射,否则会报错。

  4. Phoenix 4.10 及以上的版本,可能会遇到查不出数据的情况。这是因为4.10 版本之后,Phoenix 对列的编码方式有所改变。那么如何解决这个问题呢?(官方文档地址:http://phoenix.apache.org/columnencoding.html

    在使用 Phoenix 创建表的时候,需要设置 COLUMN_ENCODED_BYTES 属性为 0,即不让 Phoenix 对 column family 进行编码。如:(只有在创建表的时候才能够设置属性。)

    CREATE TABLE "test_table" ( "ROW" varchar primary key, "0"."name" varchar) column_encoded_bytes=0;
  • 创建schema

create schema test;
  • 创建表(建完表后hbase中也会自动创建对应的表)

create table test.t_test(
       id INTEGER NOT NULL PRIMARY KEY,
       name VARCHAR,
       age INTEGER);

创建完的表名和字段名都会自动转成大写,如需小写,需在建表时给表名和字段名前后加双引号。

  • 插入/更新数据

upsert into test.t_test (id,name,age) values(1,'zhangsan',23);
upsert into test.t_test (id,name,age) values(2,'lisi',35);
upsert into test.t_test (id,name,age) values(3,'测试',66);
  • 查询插入的数据

0: jdbc:phoenix:> select * from test.t_test;
+-----+-----------+------+
| ID  |   NAME    | AGE  |
+-----+-----------+------+
| 1   | zhangsan  | 23   |
| 2   | lisi      | 35   |
| 3   | 测试        | 66   |
+-----+-----------+------+
3 rows selected (0.181 seconds)
  • 添加索引字段

create index idx_name on test.t_test(name);

如果添加索引报错:

解决方法: 在hbase-site.xml 中配置中加入,重启服务

添加如下配置到Hbase的Hregionserver节点的hbase-site.xml

    <property>
        <!-- phoenix支持索引 -->
        <name>hbase.regionserver.wal.codec</name>
        <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
    </property>
​
    <property>
        <name>hbase.region.server.rpc.scheduler.factory.class</name>
        <value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value>
        <description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>
    </property>
​
    <property>
        <name>hbase.rpc.controllerfactory.class</name>
        <value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>
        <description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>
    </property>

添加如下配置到Hbase中Hmaster节点的hbase-site.xml中

    <!-- phoenix master 配置参数 -->
    <property>
        <name>hbase.master.loadbalancer.class</name>
        <value>org.apache.phoenix.hbase.index.balancer.IndexLoadBalancer</value>
    </property>
​
    <property>
        <name>hbase.coprocessor.master.classes</name>
        <value>org.apache.phoenix.hbase.index.master.IndexMasterObserver</value>
    </property>

再次创建索引即可。

  • 查看索引

!indexes test.t_test;

  • 删除数据

delete from test.t_test where id =1;
  • 删除表

drop table test.t_test;
  • 删除schema

drop schema test;

以上在phoenix中的DDL和DML操作在hbase对应的表中也会同时触发,即操作通过phoenix来操作hbase。

  • 退出

!quit

4 使用hbase shell创建表student

hbase(main):002:0> create 'student', 'info'
Created table student
Took 2.4457 seconds
=> Hbase::Table - student
hbase(main):003:0> lsit
NameError: undefined local variable or method `lsit' for main:Object
Did you mean?  list
​
hbase(main):004:0> list
TABLE
student
1 row(s)
Took 0.0199 seconds
=> ["student"]
hbase(main):005:0> put 'student', '1001', 'info:name', '大刘'
Took 0.3448 seconds
hbase(main):006:0> put 'student', '1001', 'info:age', '100'
Took 0.0361 seconds
hbase(main):007:0> put 'student', '1002', 'info:name', '小星'
Took 0.0243 seconds
hbase(main):008:0> put 'student', '1002', 'info:age', '20'
Took 0.0247 seconds
hbase(main):009:0> scan "student"
ROW                                    COLUMN+CELL
 1001                                  column=info:age, timestamp=1605360191345, value=100
 1001                                  column=info:name, timestamp=1605360191254, value=\xE5\xA4\xA7\xE5\x88\x98
 1002                                  column=info:age, timestamp=1605360193826, value=20
 1002                                  column=info:name, timestamp=1605360191399, value=\xE5\xB0\x8F\xE6\x98\x9F
2 row(s)
Took 0.1159 seconds
hbase(main):010:0>

5 表映射-映射已有的HBase表

表映射特点:在映射表中可以进行增删改查操作,如果在 phoenix中将映射表删除,hbase 中对应的表也会被删除。

  • phoenix 命令行中执行如下命令创建对应的映射表:

CREATE TABLE IF NOT EXISTS "student" (
"ROW" VARCHAR primary key,
"info"."name" VARCHAR,
"info"."age" VARCHAR
)column_encoded_bytes=0;

注意一:HBase 中的 RowKey 映射 Phoenix 的主键,HBase 中的 Column 映射 Phoenix 的列,且使用“列簇名.列名”进行映射。

注意二:末尾要加上 column_encoded_bytes=0,不加的话 select 时会出现查不出数据的情况。

  • 查询一下可以看得到数据,说明映射成功:

0: jdbc:phoenix:> select * from "student";
+-------+-------+------+
|  ROW  | name  | age  |
+-------+-------+------+
| 1001  | 大刘    | 100  |
| 1002  | 小星    | 20   |
+-------+-------+------+
2 rows selected (0.113 seconds)

创建映射后 HBase 里表的数据可能会被清空,我们在 HBase 那边重新插入数据即可。

  • hbasephoenix 无论哪一端插入/更新/删除数据,另一端对应的表都会同步插入/更新/删除。比如我们在 phoenix 这边插入一条数据:

0: jdbc:phoenix:> upsert into "student" values('1003','hangge','1');
1 row affected (0.111 seconds)
0: jdbc:phoenix:> select * from "student";
+-------+---------+------+
|  ROW  |  name   | age  |
+-------+---------+------+
| 1001  | 大刘      | 100  |
| 1002  | 小星      | 20   |
| 1003  | hangge  | 1    |
+-------+---------+------+
3 rows selected (0.044 seconds)
0: jdbc:phoenix:> upsert into "student" values('1004','swphonix','132');
1 row affected (0.018 seconds)
0: jdbc:phoenix:> select * from "student";
+-------+-----------+------+
|  ROW  |   name    | age  |
+-------+-----------+------+
| 1001  | 大刘        | 100  |
| 1002  | 小星        | 20   |
| 1003  | hangge    | 1    |
| 1004  | swphonix  | 132  |
+-------+-----------+------+
4 rows selected (0.05 seconds)
0: jdbc:phoenix:>
  • hbase 这边也可以看到最新插入的数据:

hbase(main):001:0> scan "student"
ROW                                    COLUMN+CELL
 1001                                  column=info:age, timestamp=1605360191345, value=100
 1001                                  column=info:name, timestamp=1605360191254, value=\xE5\xA4\xA7\xE5\x88\x98
 1002                                  column=info:age, timestamp=1605360193826, value=20
 1002                                  column=info:name, timestamp=1605360191399, value=\xE5\xB0\x8F\xE6\x98\x9F
 1003                                  column=info:_0, timestamp=1605362895354, value=x
 1003                                  column=info:age, timestamp=1605362895354, value=1
 1003                                  column=info:name, timestamp=1605362895354, value=hangge
 1004                                  column=info:_0, timestamp=1605362990307, value=x
 1004                                  column=info:age, timestamp=1605362990307, value=132
 1004                                  column=info:name, timestamp=1605362990307, value=swphonix

6 视图映射-映射已有的HBase表

视图映射特点:在映射表中只能进行查询操作,而不可以进行增删改操作。如果将 phoenix 中的映射表删除,hbase 中对应的表不会被删除。所以如果是“只读不写”最好使用视图映射,避免误删数据。

  • phoenix 命令行中执行如下命令创建对应的映射视图:

CREATE VIEW "student" (
"ROW" VARCHAR primary key,
"info"."name" VARCHAR,
"info"."age" VARCHAR
) as select * from "student";

需要注意的是 4.10之后的phoenix版本不能先创建表映射,再创建 视图映射。 否则会报错如下:

解决方法:新创建表格,把原来的数据导入新表中。

新建一个新的原生hbase表student_new或在另一个schema下创建原生hbase表TEST:student,在hbase的shell命令行中:

hbase(main):008:0> create 'student_new', 'info'
Created table student_new
...
hbase(main):009:0> create 'TEST:student', 'info'
Created table TEST:student
...
put 'TEST:student', '1001', 'info:name', '大刘'
put 'TEST:student', '1001', 'info:age', '100'
put 'TEST:student', '1002', 'info:name', '小星'
put 'TEST:student', '1002', 'info:age', '20'
put 'TEST:student', '1003', 'info:name', 'hangge'
put 'TEST:student', '1003', 'info:age', '1'
put 'TEST:student', '1004', 'info:name', 'swphonix'
put 'TEST:student', '1004', 'info:age', '132'
hbase(main):005:0> scan 'TEST:student'
ROW                                    COLUMN+CELL
 1001                                  column=info:age, timestamp=1605403412853, value=100
 1001                                  column=info:name, timestamp=1605403388226, value=\xE5\xA4\xA7\xE5\x88\x98
 1002                                  column=info:age, timestamp=1605403466025, value=20
 1002                                  column=info:name, timestamp=1605403438041, value=\xE5\xB0\x8F\xE6\x98\x9F
 1003                                  column=info:age, timestamp=1605405545685, value=1
 1003                                  column=info:name, timestamp=1605405545616, value=hangge
 1004                                  column=info:age, timestamp=1605405547490, value=132
 1004                                  column=info:name, timestamp=1605405545787, value=swphonix
  • phoenix 命令行中执行如下命令创建对应的映射视图:

CREATE VIEW test."student" (
"ROW" VARCHAR primary key,
"info"."name" VARCHAR,
"info"."age" VARCHAR
) column_encoded_bytes=0;
0: jdbc:phoenix:> CREATE VIEW test."student" (
. . . . . . . . > "ROW" VARCHAR primary key,
. . . . . . . . > "info"."name" VARCHAR,
. . . . . . . . > "info"."age" VARCHAR
. . . . . . . . > ) column_encoded_bytes=0;
No rows affected (7.73 seconds)
0: jdbc:phoenix:> !table
+------------+--------------+-------------+---------------+----------+------------+----------------------------+-----------------+--------------+---+
| TABLE_CAT  | TABLE_SCHEM  | TABLE_NAME  |  TABLE_TYPE   | REMARKS  | TYPE_NAME  | SELF_REFERENCING_COL_NAME  | REF_GENERATION  | INDEX_STATE  | I |
+------------+--------------+-------------+---------------+----------+------------+----------------------------+-----------------+--------------+---+
|            | TEST         | IDX_NAME    | INDEX         |          |            |                            |                 | ACTIVE       | f |
|            | SYSTEM       | CATALOG     | SYSTEM TABLE  |          |            |                            |                 |              | f |
|            | SYSTEM       | FUNCTION    | SYSTEM TABLE  |          |            |                            |                 |              | f |
|            | SYSTEM       | LOG         | SYSTEM TABLE  |          |            |                            |                 |              | t |
|            | SYSTEM       | SEQUENCE    | SYSTEM TABLE  |          |            |                            |                 |              | f |
|            | SYSTEM       | STATS       | SYSTEM TABLE  |          |            |                            |                 |              | f |
|            |              | student     | TABLE         |          |            |                            |                 |              | f |
|            | TEST         | T_TEST      | TABLE         |          |            |                            |                 |              | f |
|            | TEST         | student     | VIEW          |          |            |                            |                 |              | f |
+------------+--------------+-------------+---------------+----------+------------+----------------------------+-----------------+--------------+---+
0: jdbc:phoenix:> select * from test."student";
+-------+-----------+------+
|  ROW  |   name    | age  |
+-------+-----------+------+
| 1001  | 大刘        | 100  |
| 1002  | 小星        | 20   |
| 1003  | hangge    | 1    |
| 1004  | swphonix  | 132  |
+-------+-----------+------+
4 rows selected (0.123 seconds)
  • 关于映射的注意事项

1、需要将原有 HBase 中的表做映射才能后使用 Phoenix 操作。

2、Phoenix 区分大小写,切默认情况下会将小写转成大写,所以表名、列簇、列名需要用双引号。

3、Phoenix 4.10 版本之后,在创建表映射时需要将 COLUMN_ENCODED_BYTES 置为 0。

4、删除映射表,会同时删除原有 HBase 表。所以如果只做查询操作,建议做视图映射。

 

7 通过DBeaver连接Phoenix操作HBase

7.1 下载及安装

DBeaver官方:https://dbeaver.io/

下载社区版本进行安装即可:https://dbeaver.io/files/dbeaver-ce-latest-x86_64-setup.exe

7.2 启动及准备驱动包

启动DBeaver

  • 准备好驱动包

到Phoenix安装路径下(/home/hadoop/phoenix-5.0.0-HBase-2.0),复制 phoenix-5.0.0-HBase-2.0-client.jar 到本机(不同版本的Phoenix的jar命名不同,但是都是client这个包)

[root@hd120 phoenix-5.0.0-HBase-2.0]# ls -l *client.jar
-rw-r--r-- 1 root root 135109092 11月 12 15:09 phoenix-5.0.0-HBase-2.0-client.jar
-rw-r--r-- 1 root root  34159398 11月 12 15:09 phoenix-5.0.0-HBase-2.0-thin-client.jar

到hbase配置目录下(/home/hadoop/hbase/conf),复制下载 hbase-site.xml到本机

hbase-site.xml直接拖放到phoenix-5.0.0-HBase-2.0-client.jar里面(相当于把hbase-site.xml压缩进phoenix-5.0.0-HBase-2.0-client.jar包里)(可以使用WinRAR进行操作)

7.3 创建数据库连接 

  • 数据库 > 新建连接

  • 下一步:填写ip和端口 (zk集群的主机地址或主机名、端口2181)

  • 编辑驱动设置

  • 添加驱动:

    点击“添加文件”,选择准备好的phoenix-5.0.0-HBase-2.0-client.jar

    如果此时驱动包有多个,请务必删除,只保留手动添加的phoenix-5.0.0-HBase-2.0-client.jar

  • 找到驱动类 点击“找到类”,选择 org.apache.phoenix.jdbc.PhoenixDriver

  • 添加 Zookeeper Base Path 手动添加Zookeeper Base Path,这个路径可以在hbase的页面看到 (http://hd100:16010/master-status

  • C:\Windows\System32\drivers\etc\hosts添加主机列表

###hbase
192.168.26.100 hd100
192.168.26.110 hd110
192.168.26.120 hd120
  • 测试连接

7.4 操作指引 

  • 成功连接Phoenix,导航面板及浏览表、视图

  • 愉快的使用SQL查询

点击SQL编辑器,新建SQL编辑器,输入SQL语句进行查询。 注意:SQL语句结尾不能带分号(;),执行的时候会自动加上;表名和字段名使用双引号,字符串值使用单引号

SELECT * FROM test."student" WHERE "name"='swphonix'


--OK--

系列文章

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值