热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

hive安装及操作

安装元素数据存储选择默认使用derby数据库,不能够多个用户同时使用,多用于测试使用MySQL数据库存储元数据,多用于生产环境HDFS数据仓库目录创建数据仓库目录hadoopfs-
安装

元素数据存储选择

默认使用derby数据库,不能够多个用户同时使用,多用于测试
使用MySQL数据库存储元数据,多用于生产环境

HDFS数据仓库目录

  • 创建数据仓库目录
    hadoop fs -mkdir -p /user/hive/warehouse

  • 赋予权限
    hadoop fs -chmod a+w /user/hive/warehouse
    hadoop fs -chmod a+w /temp

hive安装

  • hadoop 用户将HIVE安装包解压到/home/hadoop/apps安装目录
    tar -zxvf apache-hive-1.2.2-bin.tar.gz -C /home/hadoop/apps

  • 切换到root用户
    创建软连接
    ln -s /home/hadoop/apps/hive-1.2.2 /usr/local/hive
    修改属主
    chown -R hadoop:hadoop /usr/local/hive
    添加环境变量
    vim /etc/profile
    添加内容
    export HIVE_HOME=/usr/local/hive
    export PATH=$PATH:${HIVE_HOME}/bin

使环境变量生效
source /etc/profile

切换到hadoop用户
修改HIVE_HOME/conf/hive-site.xml内容,没有则新建






javax.jdo.option.ConnectionURL
jdbc:mysql://192.168.183.101:3306/hive?createDatabaseIfNotExist=true&characterEncoding=UTF-8
JDBC connect string for a JDBC metastore


javax.jdo.option.ConnectionDriverName
com.mysql.jdbc.Driver
Driver class name for a JDBC metastore


javax.jdo.option.ConnectionUserName
hive
username to use against metastore database


javax.jdo.option.ConnectionPassword
hive123
password to use against metastore database


注: 修改对应ip和密码

启动hive
/usr/local/hive/bin/hive

[hadoop@hadoop4 bin]$ hive
Logging initialized using configuration in jar:file:/home/hadoop/apps/apache-hive-1.2.2-bin/lib/hive-common-1.2.2.jar!/hive-log4j.properties
hive>

启动成功

hive -hiveconf hive.root.logger=DEBUG,console
显示日志方式启动hive

Hive 操作

  • 查看数据库
    show databases

hive> show databases;
OK
default
Time taken: 0.02 seconds, Fetched: 1 row(s)

  • 创建数据库
    create database mytestDB;
    create database IF NOT EXISTS mytestDB;
    hadoop fs -ls /user/hive/warehouse
    会增加mytestdb.db目录
  • 选择数据库
    use mytestdb
  • 查看表
    show tables;
  • 创建表
    创建用户表:user_info
    字段信息:用户id,地域id,年龄,职业

create table user_info(
user_id string,
area_id string,
age int,
occupation string
)
row format delimited fields terminated by '\t'
lines terminated by '\n'
stored as textfile;

创建成功后,同时会在HDFS中创建目录
/user/hive/warehouse/mytestdb.db/user_info

  • 删除表
    drop table user_info;
    user_info表在hdfs的目录也会被同时删除

创建内部表

  • 在数据库rel 中创建学生信息表

create table student_info(
student_id string comment '学号',
name string comment '姓名',
age int comment '年龄',
origin string comment '地域'
)
comment '学生信息表'
row format delimited
fields terminated by '\t'
lines terminated by '\n'
stored as textfile;

  • 使用load从本地加载数据到student_info
    load data local inpath '/home/hadoop/apps/hive_test_data/student_info_data.txt' into table student_info;
    查看student_info表在hdfs路径,新增加了student_info_data.txt文件

Found 1 items
-rwxrwxrwx 3 hadoop supergroup 341 2018-01-26 10:34 /user/hive/warehouse/mydb.db/student_info/student_info_data.txt

  • 查询origin为 11 的学生
    hive> select * from student_info where origin='11'

hive> select * from student_info where origin='11'
> ;
OK
1 xiaoming 20 11
6 zhangsan 20 11
7 lisi 19 11
Time taken: 0.473 seconds, Fetched: 3 row(s)
hive>

  • 使用load将hdfs文件加载到student_info表中
    上传文件到HDFS中
    hadoop fs -put student_info_data.txt /

追加的方式载入
load data inpath '/student_info_data.txt' into table student_info;
hdfs中student_info表位置会出现两个 student_info_data.txt

[hadoop@hadoop1 sbin]$ hadoop fs -ls /user/hive/warehouse/mydb.db/student_info
Found 2 items
-rwxrwxrwx 3 hadoop supergroup 341 2018-01-26 10:34 /user/hive/warehouse/mydb.db/student_info/student_info_data.txt
-rwxrwxrwx 3 hadoop supergroup 341 2018-01-26 10:39 /user/hive/warehouse/mydb.db/student_info/student_info_data_copy_1.txt

并且HDFS中 /student_info_data.txt会剪切到student_info表的hdfs路径下/user/hive/warehouse/rel.db/student_info

以重写的方式载入
load data inpath '/student_info_data.txt' overwrite into table student_info;
会覆盖原来的数据.

数据类型

  • 创建员工表:employee
    字段信息:用户id,工资,工作过的城市,社保缴费情况(养老,医保),福利(吃饭补助(float),是否转正(boolean),商业保险(float))

create table employee(
user_id string,
salary int,
worked_citys array,
social_security map,
welfare struct
)
row format delimited fields terminated by '\t'
collection items terminated by ','
map keys terminated by ':'
lines terminated by '\n'
stored as textfile;

  • 从本地加载数据到表employee
    load data local inpath '/home/hadoop/apps/hive_test_data/employee_data.txt' into table employee;

hive> select * from employee;
OK
zhangsan 10800 ["beijing","shanghai"] {"养老":1000.0,"医疗":600.0} {"meal_allowance":2000.0,"if_regular":true,"commercial_insurance":500.0}
lisi 20000 ["beijing","nanjing"] {"养老":2000.0,"医疗":1200.0} {"meal_allowance":2000.0,"if_regular":false,"commercial_insurance":500.0}
wangwu 17000 ["shanghai","nanjing"] {"养老":1800.0,"医疗":1100.0} {"meal_allowance":2000.0,"if_regular":true,"commercial_insurance":500.0}

  • 查询已转正的员工编号,工资,工作过的第一个城市,社保养老缴费情况,福利餐补金额

hive> select user_id,
> salary,
> worked_citys[0],
> social_security['养老'],
> welfare.meal_allowance
> from employee
> where welfare.if_regular=true;
OK
zhangsan 10800 beijing 1000.0 2000.0
wangwu 17000 shanghai 1800.0 2000.0

创建外部表

可以提前创建好HDFS路径
hadoop mkdir -p /user/hive/warehouse/data/student_school_info
如果没有提前创建好,在创建外部表的时候会根据指定路径自动创建

  • 创建外部学生入学信息表
    字段信息:
    学号、姓名、学院id、专业id、入学年份
    HDFS数据路径:/user/hive/warehouse/data/student_school_info

create external table rel.student_school_info(
student_id string,
name string,
institute_id string,
major_id string,
school_year string
)
row format delimited
fields terminated by '\t'
lines terminated by '\n'
stored as textfile
location '/user/hive/warehouse/data/student_school_info';

  • 上传本地数据文件到HDFS
    hadoop fs -put /home/hadoop/apps/hive_test_data/student_school_info_external_data.txt /user/hive/warehouse/data/student_school_info/
    查询
    select * from student_school_info

创建内部分区表

创建学生入学信息表
字段信息:学号、姓名、学院id
分区字段:专业id

create table student_school_info_partition_maj(
student_id string,
name string,
institute_id string
)
partitioned by(major_id string)
row format delimited
fields terminated by '\t'
lines terminated by '\n'
stored as textfile;

  • 使用insert into从student_school_info表将2017年入学的学籍信息导入到student_school_info_partition_maj分区表中

insert into table student_school_info_partition_maj partition(major_id ='bigdata')
select t1.student_id,t1.name,t1.institute_id
from student_school_info t1
where t1. major_id = bigdata;

  • 查看分区
    show partitions student_school_info_partition_maj;

  • 查看hdfs路径,会增加major_id =’bigdata’目录
    hadoop fs -ls /user/hive/warehouse/rel.db/student_school_info_partition_maj/

  • 删除分区
    alter table student_school_info_partition drop partition (major_id ='bigdata');

  • 查看分区表,数据已经被删除

  • 使用动态分区添加数据

set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table student_school_info_partition_maj partition(major_id)
select t1.student_id,t1.name,t1.institute_id,t1.major_id
from student_school_info t1 ;

  • 查看分区
    show partitions student_school_info_partition_maj;

hive> show partitions student_school_info_partition_maj;
OK
major_id=bigdata
major_id=computer
major_id=software
Time taken: 0.114 seconds, Fetched: 3 row(s)

  • 查看hdfs路径

[hadoop@hadoop1 sbin]$ hadoop fs -ls /user/hive/warehouse/rel.db/student_school_info_partition_maj
Found 3 items
drwxrwxrwx - hadoop supergroup 0 2018-01-26 11:30 /user/hive/warehouse/rel.db/student_school_info_partition_maj/major_id=bigdata
drwxrwxrwx - hadoop supergroup 0 2018-01-26 11:30 /user/hive/warehouse/rel.db/student_school_info_partition_maj/major_id=computer
drwxrwxrwx - hadoop supergroup 0 2018-01-26 11:30 /user/hive/warehouse/rel.db/student_school_info_partition_maj/major_id=software

会增加三个目录,每个目录存储对应的数据

创建外部分区表

创建学生入学信息表
字段信息:学号、姓名、学院id
分区字段:专业id

create external table rel.student_school_info_external_partition_maj(
student_id string,
name string,
institute_id string
)
partitioned by(major_id string)
row format delimited
fields terminated by '\t'
lines terminated by '\n'
stored as textfile
location '/user/hive/warehouse/data/student_school_info_external_partition_maj';

  • 动态分区

set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table student_school_info_external_partition_maj partition(major_id)
select t1.student_id,t1.name,t1.institute_id,t1.major_id
from student_school_info t1;

  • 删除内部分区表,表删除,hdfs中的数据也删除了

drop table student_school_info_partition_maj;
[hadoop@hadoop1 sbin]$ hadoop fs -ls /user/hive/warehouse/rel.db/
Found 1 items
drwxrwxrwx - hadoop supergroup 0 2018-01-26 11:23 /user/hive/warehouse/rel.db/student_school_info_partition

  • 删除外部分区表

hive> drop table student_school_info_external_partition_maj;
OK
Time taken: 0.63 seconds
hive> show tables;
OK
student_school_info
student_school_info_partition
Time taken: 0.027 seconds, Fetched: 2 row(s)

查看hdfs中的文件,数据依然存在

[hadoop@hadoop1 sbin]$ hadoop fs -ls /user/hive/warehouse/data/
Found 2 items
drwxrwxrwx - hadoop supergroup 0 2018-01-26 11:06 /user/hive/warehouse/data/student_school_info
drwxrwxrwx - hadoop supergroup 0 2018-01-26 11:47 /user/hive/warehouse/data/student_school_info_external_partition_maj
[hadoop@hadoop1 sbin]$ hadoop fs -ls /user/hive/warehouse/data/student_school_info_external_partition_maj
Found 3 items
drwxrwxrwx - hadoop supergroup 0 2018-01-26 11:47 /user/hive/warehouse/data/student_school_info_external_partition_maj/major_id=bigdata
drwxrwxrwx - hadoop supergroup 0 2018-01-26 11:47 /user/hive/warehouse/data/student_school_info_external_partition_maj/major_id=computer
drwxrwxrwx - hadoop supergroup 0 2018-01-26 11:47 /user/hive/warehouse/data/student_school_info_external_partition_maj/major_id=software
[hadoop@hadoop1 sbin]$ hadoop fs -ls /user/hive/warehouse/data/student_school_info_external_partition_maj/major_id=software
Found 1 items
-rwxrwxrwx 3 hadoop supergroup 46 2018-01-26 11:47 /user/hive/warehouse/data/student_school_info_external_partition_maj/major_id=software/000000_0

使用LIKE、AS创建表,表重命名,添加、修改、删除列

  • 根据已存在的表结构,使用like关键字,复制一个表结构一模一样的新表
    create table student_info2 like student_info;

  • 根据已经存在的表,使用as关键字,创建一个与查询结果字段一致的表,同时将查询结果数据插入到新表
    create table student_info3 as select * from student_info;
    只有student_id,name两个字段的表
    create table student_info4 as select student_id,name from student_info;

  • student_info4表重命名为student_id_name
    alter table student_info4 rename to student_id_name;

  • 给student_info3表添加性别列,新添加的字段会在所有列最后,分区列之前,在添加新列之前已经存在的数据文件中
    如果没有新添加列对应的数据,在查询的时候显示为空。添加多个列用逗号隔开
    alter table student_info_new3 add columns (gender string comment '性别');

  • 删除列或修改列

    • 修改列,将继续存在的列再定义一遍,需要替换的列重新定义
      alter table student_info_new3 replace columns(student_id string,name string,age int,origin string,gender2 int);

    • 删除列,将继续存在的列再定义一遍,需要删除的列不再定义
      alter table student_info_new3 replace columns(student_id string,name string,age int,origin string);

创建分桶表

按照指定字段取它的hash散列值分桶
创建学生入学信息分桶表
字段信息:学号、姓名、学院ID、专业ID
分桶字段:学号,4个桶,桶内按照学号升序排列

create table rel.student_info_bucket(
student_id string,
name string,
age int,
origin string
)
clustered by (student_id) sorted by (student_id asc) into 4 buckets
row format delimited
fields terminated by '\t'
lines terminated by '\n'
stored as textfile;

  • 插入数据

set hive.enforce.bucketing = true;
set mapreduce.job.reduces=4;
insert overwrite table student_info_bucket
select student_id,name,age,origin
from student_info
cluster by(student_id);

分桶表一般不使用load向分桶表中导入数据,因为load导入数据只是将数据复制到表的数据存储目录下,hive并不会
在load的时候对数据进行分析然后按照分桶字段分桶,load只会将一个文件全部导入到分桶表中,并没有分桶。一般
采用insert从其他表向分桶表插入数据。
分桶表在创建表的时候只是定义表的模型,插入的时候需要做如下操作:
在每次执行分桶插入的时候在当前执行的session会话中要设置hive.enforce.bucketing = true;声明本次执行的是一次分桶操作。
需要指定reduce个数与分桶的数量相同set mapreduce.job.reduces=4,这样才能保证有多少桶就生成多少个文件。
如果定义了按照分桶字段排序,需要在从其他表查询数据过程中将数据按照分区字段排序之后插入各个桶中,分桶表并不会将各分桶中的数据排序。
排序和分桶的字段相同的时候使用Cluster by(字段),cluster by 默认按照分桶字段在桶内升序排列,如果需要在桶内降序排列,
使用distribute by (col) sort by (col desc)组合实现。

set hive.enforce.bucketing = true;
set mapreduce.job.reduces=4;
insert overwrite table student_info_bucket
select student_id,name,age,origin
from student_info
distribute by (student_id) sort by (student_id desc);

导出数据

  • 使用insert将student_info表数据导出到本地指定路径
    insert overwrite local directory '/home/hadoop/apps/hive_test_data/export_data' row format delimited fields terminated by '\t' select * from student_info;
  • 导出数据到本地的常用方法
    hive -e"select * from rel.student_info"> ./student_info_data.txt
    默认结果分隔符:’\t’

join关联

  • join 或者inner join
    两个表通过id关联,只把id值相等的数据查询出来。join的查询结果与inner join的查询结果相同。

select * from a join b on a.id=b.id;
等同于
select * from a inner join b on a.id=b.id;

  • full outer join 或者 full join
    两个表通过id关联,把两个表的数据全部查询出来
    select * from a full join b on a.id=b.id;

  • left join
    左连接时,左表中出现的join字段都保留,右表没有连接上的都为空
    select * from a left join b on a.id=b.id;

  • rightjoin
    右连接时,右表中出现的join字段都保留,左表没有连接上的都是空
    select * from a right join b on a.id=b.id;

  • left semi join
    左半连接实现了类似IN/EXISTS的查询语义,输出符合条件的左表内容。
    hive不支持in …exists这种关系型数据库中的子查询结构,hive暂时不支持右半连接。

select a.id, a.name from a where a.id in (select b.id from b);
使用Hive对应于如下语句:
select a.id,a.name from a left semi join b on a.id = b.id;

  • map side join
    使用分布式缓存将小表数据加载都各个map任务中,在map端完成join,map任务输出后,不需要将数据拷贝到reducer阶段再进行join,
    降低的数据在网络节点之间传输的开销。多表关联数据倾斜优化的一种手段。多表连接,如果只有一个表比较大,其他表都很小,
    则join操作会转换成一个只包含map的Job。运行日志中会出现Number of reduce tasks is set to 0 since there’s no reduce operator
    没有reduce的提示。
    select /*+ mapjoin(b) */ a.id, a.name from a join b on a.id = b.id

hive 内置函数

  • case when
    语法1:CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END
    说明:如果a等于b,那么返回c;如果a等于d,那么返回e;否则返回f

hive> select case 1 when 2 then 'two' when 1 then 'one' else 'zero' end;
one

语法2:CASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END
说明:如果a为TRUE,则返回b;如果c为TRUE,则返回d;否则返回e

hive> select case when 1=2 then 'two' when 1=1 then 'one' else 'zero' end;
one

自定义UDF函数

当Hive提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数(UDF:user-defined function)。
UDF 作用于单个数据行,产生一个数据行作为输出。
步骤:

  • 先开发一个java类,继承UDF,并重载evaluate方法
  • 打成jar包上传到服务器
  • 在使用的时候将jar包添加到hive的classpath
    hive>add jar /home/hadoop/apps/hive_test_data/HiveUdfPro-1.0-SNAPSHOT.jar;
  • 创建临时函数与开发好的java class关联
    hive>create temporary function age_partition as ‘cn.hadoop.udf.AgePartitionFunction’;
  • 即可在hql中使用自定义的函数
    select gender,
    age_partition(age),
    max(core) max_core
    from rel.user_core_info
    group by gender,
    age_partition(age);

HIVE安装使用时遇到的问题

  1. 创建表时失败

原因: mysql字符集问题,要设置mysql中hive数据库的字符为latin1

  1. 删除表时,卡主
    原因: 也是字符问题. 是在创建表时,mysql的字符还是utf-8, 后来用命令改掉为latin1,
    需要重新设置,删除hive数据库,重新创建,并设置字符集.

推荐阅读
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 推荐一个ASP的内容管理框架(ASP Nuke)的优势和适用场景
    本文推荐了一个ASP的内容管理框架ASP Nuke,并介绍了其主要功能和特点。ASP Nuke支持文章新闻管理、投票、论坛等主要内容,并可以自定义模块。最新版本为0.8,虽然目前仍处于Alpha状态,但作者表示会继续更新完善。文章还分析了使用ASP的原因,包括ASP相对较小、易于部署和较简单等优势,适用于建立门户、网站的组织和小公司等场景。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 本文介绍了关于apache、phpmyadmin、mysql、php、emacs、path等知识点,以及如何搭建php环境。文章提供了详细的安装步骤和所需软件列表,希望能帮助读者解决与LAMP相关的技术问题。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 本文介绍了在MacOS系统上安装MySQL的步骤,并详细说明了如何设置MySQL服务的开机启动和如何修改MySQL的密码。通过下载MySQL的macos版本并按照提示一步一步安装,在系统偏好设置中可以找到MySQL的图标进行设置。同时,还介绍了通过终端命令来修改MySQL的密码的具体操作步骤。 ... [详细]
  • C语言常量与变量的深入理解及其影响
    本文深入讲解了C语言中常量与变量的概念及其深入实质,强调了对常量和变量的理解对于学习指针等后续内容的重要性。详细介绍了常量的分类和特点,以及变量的定义和分类。同时指出了常量和变量在程序中的作用及其对内存空间的影响,类似于const关键字的只读属性。此外,还提及了常量和变量在实际应用中可能出现的问题,如段错误和野指针。 ... [详细]
author-avatar
淑圣承琦9_416
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有