• Linux----------mysql基础


    一、数据库介绍

    数据库是数据的汇集,它以一定的组织形式存于存储介质上
    DBMS是管理数据库的系统软件,它实现数据库系统的各种功能。是数据库系统的核心
    DBA:负责数据库的规划、设计、协调、维护和管理等工作
    应用程序指以数据库为基础的应用程序
    

    1.1 数据库的优点

    相互关联的数据的集合 
    较少的数据冗余
    程序与数据相互独立
    保证数据的安全、可靠
    最大限度地保证数据的正确性
    数据可以并发使用并能同时保证一致性
    

    1.2 数据库的基本功能

    • 数据定义
    • 数据处理
    • 数据安全
    • 数据备份

    1.3数据库的类型

    • 关系型数据:mysql,mariadb,oracle为代表
    • 非关系型数据库nosql :redis,memached,mongodb

    1.4 关系型数据的组成

    • 关系:关系是二维表,并满足如下性质:表中的行、列次序并不重要
    • 行row:表中的的每一行,又称为一条记录
    • 列coloumn:表中的每一列,称为属性,字段
    • 主键(Primary key):用于唯一确定一个记录的字段
    • 域domain:属性的取值范围,如性别只能是男和女
    • 事务transaction:多个操作被当作一个整体对待
    • ACID:
      A:原子性
      B:一致性
      C:隔离性
      D:持久性

    1.5 关系型数据库的常用组件

    关系型数据库的常用组件有:

    • 数据库: database
    • 表:table,由行(row)和列(column)组成
    • 索引:index
    • 视图:view
    • 用户:user
    • 权限:privilege
    • 存储过程:procedure
    • 存储函数:function
    • 触发器:trigger
    • 事件调度器:event scheduler

    1.6 SQL语句

    SQ语句有三种类型:

    • DDL:Data Defination Langusage---数据定义语言
    • DML:Data Manipulation Language---数据操纵语言
    • DCL:Data Control Language---数据控制语言

    SQL语句类型 对应操作

    DDL	        CREATE:创建  
                    DROP:删除  
                    ALTER:修改
    DML	INSERT:向表中插入数据
                    DELETE:删除表中数据
                    UPDATE:更新表中数据
                    SELECT:查询表中数据
    DCL	        GRANT:授权
                    REVOKE:移除授权
    

    1.7 mysql命令使用

    //语法:mysql [options] [databases]
    //常用的option:
    -u username //指定用户名,默认为root
    -p password //指定用户的密码
    -h host //指定服务器主机,默认为localhost,推荐使用IP地址
    -V //查看当前使用的mysql版本
    -P# //指定数据库监听的端口,这里#指的是实际的端口 ,默认为3306
    -e //不登录mysql执行sql语句后退出,常用于脚本

    1.8服务器监听的两种socket

    ip socket : 默认监听在tcp的3306端口,支持远程通信
    Unix socket: 监听在sock文件上(tmp/mysql.sock,/var/lib/mysql/mysql.mysql.socket),仅支持本地通信,server地址只能是:localhost,127.0.0.1

    二、mysql安装和配置

    mysql安装方式有三种:
    源码:编译安装
    二进制:二进制格式的程序包(已编译好)展开特定路径,并经过简单配置后即可使用
    yum:yum install直接安装最简单,但是使用的模块不能按需配置,日志和配置文件统一管理不方便

    这里主要讲下mysql的yum安装和源码编译安装

    2.1 mysql-yum安装

    //配置好自己的yum源,以及网络源
    wget http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm
    yum -y install mysql57-community-release-el7-10.noarch.rpm
    yum -y install mysql-community-server mysql-community-client mysql-community-common mysql-community-devel
    
    //启动mysql并初始化(必须修改初始密码)
    systemctl start mysqld
    
    //确保默认的3306端口已经监听起来
    ss -ntlp  
    
    //日志文件中找出临时密码
    grep "password" /var/log/mysqld.log
    
    //登录mysql
    mysql -uroot  -p"临时密码"
    
    //修改mysql登录密码
    set global validate_password_policy=0;
    set global validate_password_length=1;
     ALTER USER 'root'@'localhost' IDENTIFIED BY 'wang123';
    //修改完退出测试能否进去
    
    //为避免mysql自动升级,这里需要卸载最开始安装的yum源
    mysql -v (记住mysql版本)
    yum -y remove mysql57-community-release-el7-10.noarch
    

    2.2 msyql编译安装

    //配置好网络yum源,安装依赖软件包和开发包组,编译工具
    yum gropuinstall   "Development tools"
    yum   install yum install libaio-devel bison bison-devel zlib-devel
    openssl-devel ncurses-devel libcurl-devel libarchive-devel
    boost-devel gcc gcc-c++ cmake libevent-devel  -y
    
    //j检查本机是否安装mysql数据库,如果有就卸载
    rpm -qa mysql
    systemctl stop mysqld
    rpm -ev  mysql-server*
    rpm -qa mysql
    
    //编译安装mysql前需要先创建mysql用户和组,创建mysql安装目录和存放目录
    groupadd mysql
    useradd -M -s /sbin/nologin -g mysql mysql
    mkdir -p /data/mysql
    chown -R msyql.mysql /data/mysql
    mkdir -p  /usr/local/mysql
    
    //编译源码包
    cd /usr/local/
    wget  https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.26.tar.gz
    tar -xvf mysql-5.7.26.tar.gz
    cd mysql-5.7.26.tar.gz
    cmake . 
    DCMAKE_INSTALL_PREFIX=/usr/local/mysql 
    DMYSQL_DATADIR=/data/mysql/ 
    DSYSCONFDIR=/etc 
    DMYSQL_USER=mysql 
    DWITH_INNOBASE_STORAGE_ENGINE=1 
    DWITH_ARCHIVE_STORAGE_ENGINE=1 
    DWITH_BLACKHOLE_STORAGE_ENGINE=1 
    DWITH_PARTITION_STORAGE_ENGINE=1 
    DWITHOUT_MROONGA_STORAGE_ENGINE=1 
    DWITH_DEBUG=0 
    DWITH_READLINE=1 
    DWITH_SSL=system 
    DWITH_ZLIB=system 
    DWITH_LIBWRAP=0 
    DENABLED_LOCAL_INFILE=1 
    DMYSQL_UNIX_ADDR=/tmp/mysql.sock 
    DDEFAULT_CHARSET=utf8 
    DDEFAULT_COLLATION=utf8_general_ci
    make && make install
    
    //准备环境变量
    echo 'PATH=/app/mysql/bin:$PATH' > /etc/profile.d/mysql.sh
    . /etc/profile.d/mysql.sh
    
    //生成数据库文件
    cd /usr/local/mysql/
    scripts/mysql_install_db --datadir=/data/mysql/ --
    user=mysql
    
    //准备配置文件
    cp /usr/local/mysql/support-files/my-huge.cnf /etc/my.cnf
    
    //准备启动脚本
    cp /app/mysql/support-files/mysql.server /etc/init.d/mysqld
    
    //启动服务
    chkconfig --add mysqld ;service mysqld start
    

    三、SQL语言用法详解

    3.1 DDL-数据库操作

    //创建数据库:
    CREATE DATABASE|SCHEMA [IF NOT EXISTS] 'DB_NAME';
    CHARACTER SET 'character set name'
    COLLATE 'collate name'
    //删除数据库
    DROP DATABASE|SCHEMA [IF EXISTS] 'DB_NAME';
    //查看支持所有字符集:SHOW CHARACTER SET;
    //查看支持所有排序规则:SHOW COLLATION;
    //获取命令使用帮助:
    mysql> HELP KEYWORD;
    //查看数据库列表:
    mysql> SHOW DATABASES;
    

    3.12 创建表

    创建表: CREATE TABLE
    (1) 直接创建
    (2) 通过查询现存表创建;新表会被直接插入查询而来的数据
    CREATE [TEMPORARY] TABLE [IF NOT EXISTS]  tbl_name [(create_definition,...)] [table_options]  [partition_options] select_statement
    (3) 通过复制现存的表的表结构创建,但不复制数据
    CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name { LIKE old_tbl_name | (LIKE old_tbl_name) }
    注意:
    Storage Engine是指表类型,也即在表创建时指明其使用的存储引擎,同一库中不同表可以使用不同的存储引擎
    同一个库中表建议要使用同一种存储引擎类型
    CREATE TABLE [IF NOT EXISTS] ‘tbl_name’ (col1 type1 修饰符, col2 type2 修饰符, ...)
    字段信息
      col type1
      PRIMARY KEY(col1,...)
      INDEX(col1, ...)
      UNIQUE KEY(col1, ...)
    表选项:
    - ENGINE [=] engine_name
    SHOW ENGINES;查看支持的engine类型
    - ROW_FORMAT [=]
    {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}
    获取帮助:mysql> HELP CREATE TABLE;
    

    3.13 表操作

    查看所有的引擎:SHOW ENGINES
    查看表:SHOW TABLES [FROM db_name]
    查看表结构:DESC [db_name.]tb_name
    删除表:DROP TABLE [IF EXISTS] tb_name
    查看表创建命令:SHOW CREATE TABLE tbl_name
    查看表状态:SHOW TABLE STATUS LIKE 'tbl_name’
    查看库中所有表状态: SHOW TABLE STATUS FROM db_name
    

    3.14 数据类型

    数据类型:
       数据长什么样?
       数据需要多少空间来存放?
       系统内置数据类型和用户定义数据类型
    MySql支持多种列类型:
       数值类型
       日期/时间类型
       字符串(字符)类型
    选择正确的数据类型对于获得高性能至关重要,三大原则:
       更小的通常更好,尽量使用可正确存储数据的最小数据类型
       简单就好,简单数据类型的操作通常需要更少的CPU周期
       尽量避免NULL,包含为NULL的列,对MySQL更难优化
    
    (一)整型
    tinyint(m) 1个字节 范围(-128~127)
    smallint(m) 2个字节 范围(-32768~32767)
    mediumint(m) 3个字节 范围(-8388608~8388607)
    int(m) 4个字节 范围(-2147483648~2147483647)
    bigint(m) 8个字节 范围(+-9.22*10的18次方)
    取值范围如果加了unsigned,则最大值翻倍,如tinyint unsigned的取值范围为(0~255)
    int(m)里的m是表示SELECT查询结果集中的显示宽度,并不影响实际的取值范围,规定了MySQL的一些交互工具(例如MySQL命令行客端)用来显示字符的个数。对于存储和计算来说,Int(1)和Int(20)是相同的
    BOOL,BOOLEAN:布尔型, 是TINYINT(1)的同义词。zero值被视为假。非zero值视为真
    
    (二)浮点型(float和double),近似值
    float(m,d) 单精度浮点型 8位精度(4字节) m总个数,d小数位
    double(m,d) 双精度浮点型16位精度(8字节) m总个数,d小数位
    设一个字段定义为float(6,3),如果插入一个数123.45678,实际
    数据库里存的是123.457,但总个数还以实际为准,即6位
    
    (三)定点数
    在数据库中存放的是精确值,存为十进制
    decimal(m,d) 参数m<65 是总个数,d<30且 d<m 是小数位
    MySQL5.0和更高版本将数字打包保存到一个二进制字符串中(每4个字节存9个数字)。例如,decimal(18,9)小数点两边将各存储9个数字,一共使用9个字节:小数点前的数字用4个字节,小数点后的数字用4个字节,小数点本身占1个字节
    浮点类型在存储同样范围的值时,通常比decimal使用更少的空间。float使用4个字节存储。double占用8个字节
    因为需要额外的空间和计算开销,所以应该尽量只在对小数进行精确计算时才使用decimal——例如存储财务数据。但在数据量比
    较大的时候,可以考虑使用bigint代替decimal
    
    (四)字符串
    字符串(char,varchar,_text)
    char(n) 固定长度,最多255个字符
    varchar(n)可变长度,最多65535个字符
    tinytext 可变长度,最多255个字符
    text可变长度,最多65535个字符
    mediumtext 可变长度,最多2的24次方-1个字符
    longtext 可变长度,最多2的32次方-1个字符
    BINARY(M) 固定长度,可存二进制或字符,长度为0-M字节
    VARBINARY(M) 可变长度,可存二进制或字符,允许长度为0-M字节
    内建类型:ENUM枚举, SET集合
    //注意事项
    char和varchar:
    - 1.char(n) 若存入字符数小于n,则以空格补于其后,查询之时再将空格去掉。所以char类型存储的字符串末尾不能有空格,varchar不限于此。
    - 2.char(n) 固定长度,char(4)不管是存入几个字符,都将占用4个字节,varchar是存入的实际字符数+1个字节(n< n>255),所以varchar(4),存入3个字符将占用4个字节。
    - 3.char类型的字符串检索速度要比varchar类型的快
    
    varchar和text:
    - 1.varchar可指定n,text不能指定,内部存储varchar是存入的实际字符数+1个字节(n< n>255),text是实际字符数+2个字节。
    - 2.text类型不能有默认值
    - 3.varchar可直接创建索引,text创建索引要指定前多少个字符。
    varchar查询速度快于text
    
    (五)二进制数据:BLOB
    BLOB和text存储方式不同,TEXT以文本方式存储,英文
    存储区分大小写,而Blob是以二进制方式存储,不分大小写
    BLOB存储的数据只能整体读出
    TEXT可以指定字符集,BLOB不用指定字符集
    
    (六)日期时间类型
    - date 日期 '2008-12-2'
    - time 时间 '12:25:36'
    - datetime 日期时间 '2008-12-2 22:06:44'
    - timestamp 自动存储记录修改时间
    - YEAR(2), YEAR(4):年份
    timestamp字段里的时间数据会随其他字段修改的时候自动刷新,这个
    数据类型的字段可以存放这条记录最后被修改的时间
    
    (七)修饰符
    所有类型:
    - NULL 数据列可包含NULL值
    - NOT NULL 数据列不允许包含NULL值
    - DEFAULT 默认值
    - PRIMARY KEY 主键
    - UNIQUE KEY 唯一键
    - CHARACTER SET name 指定一个字符集
    -  数值型
    - AUTO_INCREMENT 自动递增,适用于整数类型
    - UNSIGNED 无符号
    

    3.15 示例

    1.创建students表,id为主键自动增长且不能为空,name 长度最多为20且不能为空,age最多为127
    CREATE TABLE students (id int  NOT NULL PRIMARY KEY AUTO_INCREMENT,name VARCHAR(20)NOT NULL,age tinyint UNSIGNED);
    
    2.查看students表的类型
    DESC students;
    
    创建students2表,主键为id、name,id不能为空,name长度最多为20且不能为空,age最多为127
    3,CREATE TABLE students2 (id int UNSIGNED NOT NULL ,name VARCHAR(20) NOT NULL,age tinyint UNSIGNED,PRIMARY KEY(id,name));
    

    3.16 修改表示例

    ALTER TABLE students RENAME s1;
    ALTER TABLE s1 ADD phone varchar(11) AFTER name;
    ALTER TABLE s1 MODIFY phone int;
    ALTER TABLE s1 CHANGE COLUMN phone mobile char(11);
    ALTER TABLE s1 DROP COLUMN mobile;
    Help ALTER TABLE 查看帮助
    
    ALTER TABLE students ADD gender ENUM('m','f')
    ALETR TABLE students CHANGE id sid int UNSIGNED NOT NULL PRIMARY KEY;
    ALTER TABLE students ADD UNIQUE KEY(name);
    ALTER TABLE students ADD INDEX(age);
    DESC students;
    SHOW INDEXES FROM students;
    ALTER TABLE students DROP age;
    

    3.2 DML-增删改查

    DML: INSERT,DELETE,UPDATE,SELECT

    3.21 INSERT

    INSERT:一次插入一行或多行数据
    语法: INSERT [L OW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]  [INTO] tbl_name [(col_name,...)]  {VALUES | VALUE} ({expr | DEFAULT},...),(...);
    - 简化学法:INSERT tbl_name [(col1,...)] VALUES (val1,...), (val21,...)
    - 简化示例: insert  * from students where name = 'lisi'; 
    示例:
    - INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY]
    [IGNORE] [INTO] tbl_name SET col_name={expr | DEFAULT}, ... [ ON DUPLICATE KEY UPDATE col_name=expr [, col_name=expr] ... ]
    - INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)] SELECT ... [ ON DUPLICATE KEY UPDATE col_name=expr [, col_name=expr] ... ]
    

    3.22 UPDATE

    UPDATE :修改一列或多列的某个或整列数据
    UPDATE [LOW_PRIORITY] [IGNORE] table_reference SET col_name1={expr1|DEFAULT} [,col_name2={expr2|DEFAULT}] ... [WHERE where_condition] [ORDER BY ...] [LIMIT row_count]
    - 简化学法:update tbl_name  values 
    - 简化示例:update student set age = 20 where nam = 'lisi';
    注意:一定要有限制条件,否则将修改所有行的指定字段
    限制条件:
    WHERE
    LIMIT
    Mysql 选项:--safe-updates| --i-am-a-dummy|-U
    

    3.23 DELETE

    DELETE:删除具体某个或某行或某列或表的数据
    DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [WHERE where_condition] [ORDER BY ...] [LIMIT row_count]
    - 简化学法:delete tbl_name values
    - 简化示例:delete ftom studeng where name = 'lisi';
    可先排序再指定删除的行数
    注意:一定要有限制条件,否则将清空表中的所有数据
    限制条件:
    WHERE
    LIMIT
    TRUNCATE TABLE tbl_name; 清空表
    

    3.24 SELECT

    SELECT:查询具体的数据
    SELECT:SELECT [ALL | DISTINCT | DISTINCTROW ] [SQL_CACHE | SQL_NO_CACHE]
    select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [FOR UPDATE | LOCK IN SHARE MODE]
    - 简化学法:select  tbl_name values
    - 简化示例:select   * from student  where  name = 'lisi';
    
    - 字段显示可以使用别名:
    col1 AS alias1, col2 AS alias2, ...
    - WHERE子句:指明过滤条件以实现“选择”的功能:
    过滤条件:布尔型表达式
    算术操作符:+, -, *, /, %
    比较操作符:=, !=, <>, <=>, >, >=, <, <=
    BETWEEN min_num AND max_num
    IN (element1, element2, ...)
    IS NULL
    IS NOT NULL
    
    - LIKE:
    %: 任意长度的任意字符
    _:任意单个字符
    - RLIKE:正则表达式,索引失效,不建议使用
    - REGEXP:匹配字符串可用正则表达式书写模式,同上
    - 逻辑操作符:
    NOT
    AND
    OR
    XOR
    - GROUP:根据指定的条件把查询结果进行“分组”以用于做“聚合”运算
    avg(), max(), min(), count(), sum()
    HAVING: 对分组聚合运算后的结果指定过滤条件
    - ORDER BY: 根据指定的字段对查询结果进行排序
    升序:ASC
    降序:DESC
    - LIMIT [[offset,]row_count]:对查询的结果进行输出行数
    数量限制
    - 对查询结果中的数据请求施加“锁”
    FOR UPDATE: 写锁,独占或排它锁,只有一个读和写
    LOCK IN SHARE MODE: 读锁,共享锁,同时多个读
    

    3.3 DCL-授权

    授权:grant
    参考:https://dev.mysql.com/doc/refman/5.7/en/grant.html
    GRANT priv_type [(column_list)],... ON [object_type] priv_level TO 'user'@'host' [IDENTIFIED BY 'password'] [WITH GRANT OPTION]; priv_type: ALL [PRIVILEGES]
    - object_type:TABLE | FUNCTION | PROCEDURE
    - priv_level: *(所有库) | *.* | db_name.* | db_name.tbl_name
    - tbl_name(当前库的表) | db_name.routine_name(指定库的函数,存储过程,触发器)
    with_option: GRANT OPTION
    | MAX_QUERIES_PER_HOUR count
    | MAX_UPDATES_PER_HOUR count
    | MAX_CONNECTIONS_PER_HOUR count
    | MAX_USER_CONNECTIONS count
    - 简化学法:GRANT SELECT (col1), INSERT (col1,col2) ON mydb.mytbl TO 'someuser'@'somehost';
    - 简化示例: grant all privileges on *.* to 'yangxin'@'%' identified by 'yangxin123456' with grant option;
    
    - 回收授权:REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ... ON [object_type] priv_level FROM user [, user] ...
    示例:REVOKE DELETE ON testdb.* FROM 'testuser'@'%‘
    查看指定用户获得的授权:
    Help SHOW GRANTS
    SHOW GRANTS FOR 'user'@'host';
    SHOW GRANTS FOR CURRENT_USER[()];
    注意:msyql服务进程启动时会读取mysql库中所有授权表至内存
    (1) GRANT或REVOKE等执行权限操作会保存于系统表中,mysql的服务进程通常会自动重读授权表,使之生效
    (2) 对于不能够或不能及时重读授权表的命令,可手动让mysql的服务进程重读授权表:
    mysql> FLUSH PRIVILEGES;
    

    3.4 多表查询

    交叉连接:笛卡尔乘积
    内连接:
    等值连接:让表之间的字段以“等值”建立连接关系;
    不等值连接
    自然连接:去掉重复列的等值连接
    自连接
    外连接:
    左外连接:
    FROM tb1 LEFT JOIN tb2 ON tb1.col=tb2.col
    右外连接
    FROM tb1 RIGHT JOIN tb2 ON tb1.col=tb2.col

    子查询:在查询语句嵌套着查询语句,性能较差
         基于某语句的查询结果再次进行的查询
    
    用在WHERE子句中的子查询:
         用于比较表达式中的子查询;子查询仅能返回单个值
         SELECT Name,Age FROM students WHERE Age>(SELECT avg(Age) FROM students);
         用于IN中的子查询:子查询应该单键查询并返回一个或多个值从构成列表
        SELECT Name,Age FROM students WHERE Age IN (SELECT Age FROM teachers);
        用于EXISTS
    
    用于FROM子句中的子查询
    使用格式:SELECT tb_alias.col1,... FROM (SELECT clause) AS tb_alias WHERE Clause;
    示例: SELECT s.aage,s.ClassID FROM (SELECT avg(Age) AS aage,ClassID FROM students WHERE ClassID IS NOT NULL GROUP BY ClassID) AS s WHERE s.aage>30;
    - 联合查询:UNION
    SELECT Name,Age FROM students UNION
    SELECT Name,Age FROM teachers;
    

    四、注意事项

    1.truncate与delete的区别

    • delete:
    • delete删除表内容时仅删除内容,但会保留结构
    • delete语句每次删除一行,并在事务日志中为所删除的每行记录一项
    • 可以通过回滚事务日志恢复数据
    • 非常占用空间
    • truncate
    • 删除表中所有数据,且无法恢复
    • 表结构、约束和索引等保持不变,新添加的行计数值重置为初始值
    • 执行速度比DELETE快,且使用的系统和事务日志资源少
    • 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放
    • 对于有外键约束引用的表,不能使用TRUNCATE TABLE删除数据
    • 不能用于加入了索引视图的表

    2.刚安装的mysql必须修改密码以及初始化
    mysql主目录下/bin/mysqld 命令来初始化
    /usr/local/mysql/bin/mysqld --user mysql --basedir /usr/local/mysql --datadir /usr/local/mysql/data --initialize

    3.对远程客户端授权后flush privileges必须刷新权限

    4.mysql和mariadb可以当成是同一个软件,源代码一样

  • 相关阅读:
    C++ 如何判断所调用的重载函数
    C++ 入门5 类和动态内存分配(一)
    c#动态创建ODBC数据源
    设为首页,加入收藏,联系我们
    ASP.NET 2.0中CSS失效
    typedef的四个用途和两个陷阱(转)
    VC++实现应用程序对插件的支持(转)
    DOM无关事件
    How to Migrate from WCF Web API to ASP.NET Web API
    Using ASP.NET Web API with ASP.NET Web Forms
  • 原文地址:https://www.cnblogs.com/wangchengshi/p/10758623.html
Copyright © 2020-2023  润新知