码迷,mamicode.com
首页 > 数据库 > 详细

数据库(一)

时间:2018-11-20 00:09:41      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:pca   show   没事   结束   匹配   体系结构   ogr   国家标准   连接服务器   

前言

OK, 经过网络编程和并发编程的学习,现在到了学习数据库愉快之旅了??.感觉到一丝丝的兴奋,学习新知识的开始总是能够给人动力,何况还是学习数据库,一看就显得高大上,而且几乎都是命令行操作,黑客既视感有没有...

数据库介绍

什么是数据库

简单来说,数据库( DataBase)就是用来存放数据的仓库,就像 github 仓库一样是用来存放数据的,这个仓库是按照一定的数据结构(数据结构是指数据的组织形式或数据之间的联系)来组织和存储数据的,可以通过各种 SQL 语句来存取数据库里的数据.

随着计算机技术的发展和信息的爆炸,数据库不仅仅是存储和管理数据了,而转变成用户所需要的各种数据管理方式.数据库有很多种类和功能,从最简单的存储有各种数据的表格到能够进行海量数据存储的大型数据库系统都在各方面得到了广泛的应用.

数据库之前

在数据库之前是怎么存储数据的呢?

文本模型

早先的数据都是保存在文本文件中的,所以这就促使了文本文件的编辑器非常流行,文本检索的速度慢效率低,当数据库文件变得庞大时,快速的检索数据就变成了一个难题.所以出现了 DB,DB 是以给每一行做一个特定的标志的方式来工作的,这个标记叫 key, 查找一个之需要先找到 key, 这样就能快速的检索大需要的值( value).DB 是伯克利大学开发的,它早期也叫 sleepcat. 但是随着数据的增加,以及用户对检索速度的需求,这就让很多数据直接工作在了内存中,当数据文件越来越大的时候,内存的容量就成了我们的瓶颈,而有些操作是完全需要载入内存中,然后由内存工作查询之后,才将结果反馈,在这种越来越复杂的机制下,使用纯文本来保存数据已经不能满足需求了,接着出现了层次模型.

层次模型

层次模型将文本分成了像根-->下级目录—>下下级目录这样的形式.(层次模型中非常著名的是 Sybase)信息管理系统中最重要的就是数据,而如果把信息管理系统比作身体的话,数据就相当于血液,而我们的心脏,其实就是数据库.像之前的纯文本记录数据,能够实现数据记录的就是文本文件,而实现数据管理的就是检索命令.层次模型的出现,在很大程度上缓解了数据检索速度的难题,但它毕竟是按照倒置树的结构来执行的,这样的模型想要在多个节点之间建立某种联系非常困难.所以后来出现了网状模型.

网状模型

这种模型是以彼此间如何建立关联来决定的.它在层次模型的基础上对于不同的节点建立了更多的连接,使得不同节点之间的连接变得轻松简单.但是这两种模型都有一种极大的缺陷,它们需要跟软件的耦合成都非常的高,如果我们想修改一下数据模型中的关系和结构的话,则势必要完全修改对应的数据模型下的数据管理软件.之后出现了关系模型.

关系模型

关系模型其实就是一堆二维表,由行和列组成,在同一个数据库之间可以存在多张表,表与表之间还有相关的属性相关联.这样,表内之间有关系,表与表之间也有关系,这就是关系模型.而现在的关系模型经过进一步发展,有了对象---关系模型, MySQL 就是一个对象---关系模型.能够提供关系模型的就叫关系型数据库模拟系统.

数据库的作用

一个良好的数据库管理系统,都有以下功能:

  1. 管理数据存储;
  2. 安全管理,为数据库提供避免非法访问的机制,非常重要;
  3. 管理元数据,描述数据库属性的,本身跟数据无关;
  4. 事务管理,为了保证数据一致性的一个重要机制,现在大多数数据管理系统都提供事务的功能;
  5. 支持连接,主要指网络支持能力;
  6. 性能优化,在性能方面提供一定的优化机制,这是现在最流行的关系型数据管理系统的最重要的标准之一.在 RDBMS 中检索效率最高的,是 Oracle和 MySQL;
  7. 提供备份和恢复机制,对于数据库管理系统,这也是必需的功能,像 MySQL 为了数据安全,每份数据都保存两份,虽然数据冗余,但是保证了数据的安全;
  8. 提供数据检索和修改的处理机制,快速查询数据和修改数据.

数据库相关概念

数据库里存储很多数据库,一个数据库可以看做是一个文件夹,数据库里面的表可以看做由文件夹管理的文件.

在表中有许多的字段.(可以看做是描述一个数据的特征)
  • 字段
  • 记录
  • DBMS
  • 数据库服务器

数据库本质上是一套 C/S 架构的 socket 软件.

数据库分类及优缺点

在当前的互联网中,最常用的数据库模型主要是两种,即关系型数据库和非关系型数据库.

关系型数据

虽然网状数据库和层次数据库已经很好的解决了数据的几种和共享问题,但是在数据独立性和抽象性上仍有很大不足,而关系型数据库就可以较好的解决这些问题.

关系型数据库模型是把复杂的数据结构归结为简单的二元关系(即二维表格形式).在关系数据库中,对数据的操作几乎全部建立在一个或多个关系表格上,通过对这些关联表的表格分类,合并,连接或选取等运算来实现数据的管理.

关系型数据库诞生距今已有40多年,从理论产生到发展为产品,例如, MySQL 和 Oracle 数据库.Oracle 在数据库领域上升到霸主地位,形成每年高达数百亿美元的庞大市场,而 MySQL 也是一路坎坷,以至于被 Oracle 收购(先被 SUN 收购,然后 SUN 被 Oracle 收购)

总结:什么是关系型数据库

  • 二维的表格;
  • 通过 SQL 结构化查询语言来存取和管理数据;
  • 保持数据一致性方面很强

非关系数据库

非关系型数据库也称为 NoSQL,NoSQL 的本意是‘ Not Only SQL‘,指的是非关系型数据库,而不是‘No SQL‘的意思.因此, NoSQL 的产生并不是要彻底否定关系型数据库,而是作为传统关系型数据库的一个有效补充. NoSQL 数据库在特定的场景下可以发挥出难以想象的高效率和高性能.

随着互联网 web2.0网站(以前基本是静态网页)的兴起,传统的关系型数据库在应付web2.0网站,特别是对于规模日益扩大的海量数据,超大规模和高并发的微博,微信, SNS 类型的 web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,例如:传统的关系型数据库 I/O 瓶颈,性能瓶颈都难以有效突破,于是开始出现了大批针对场景,以高性能和使用便利为目的的功能特异化得数据库产品, NoSQL( 非关系型)类的数据库就是在这样的场景中诞生并得到了非常迅速的发展. NoSQL 不将数据的一致性作为重点,或者是作为次重点.

NoSQL是非关系型数据库的广泛定义.它打破了长久以来关系型数据库与 ACID 理论大统一的局面. NoSQL 数据存储不需要固定的表结构,通常也不存在连接操作.在大数据存储上具备关系型数据库无法比拟的性能优势.当今的应用体系结构需要数据存储在和兴伸缩性上能够满足需求.而 NoSQL 存储就是为了实现这个需求而诞生的.

总结:什么是非关系型数据库

  • NoSQL 不是否定关系型数据库,而是作为关系数据库的一个重要补充;
  • NoSQL 为了高性能,高并发而生,忽略影响高性能,高并发的功能.

具体分类

关系型数据库

  • Oracle: 目前最好的关系型数据库,优势在于用户管理与分布式,但是商业版收费;
  • MySQL: 免费开源,功能没有 Oracle 强大,但足以满足中小企业使用;
  • SQLserver: 属于微软生态,需要和 windows 配合使用;
  • DB2:IBM 开发的大型关系型数据库,收费,通常和硬件捆绑销售.

非关系型数据库

  • MongoDB:面向文档
  • redis:持久化缓存
  • memercach:纯内存

MySQL 数据库

Mysql 的安装

MAC 版安装

  1. 下载MySQL 社区版

    技术分享图片

  2. 安装 MySQL

    双击 mysql-5.7.24-macos10.14-x86_64.dmg 文件,加载镜像,一直点击继续,因为我已经安装了,就不演示了.注意安装成功后悔弹出一个对话框,告诉我们生成了一个 root 账户的临时密码.需要保存(实在不记得也没事,有办法修改)

  3. 启动 MySQL

    打开系统偏好设置,会发现在最下方多了一个 MySQL 图标,点击进入设置界面

    技术分享图片

    安装完成,默认 MySQL 的状态是 stopped, 需要点击 Start MySQL Server 来启动,启动之后,状态变为 running. 下方有一个设置是否开机自启动.

  4. 终端连接 MySQL

    首先把 MySQL 路径添加到环境变量中;

    技术分享图片

  5. 命令行登陆

    mysql -u root -p

    登陆成功后需要重设登录密码,否则使用不了.

    mysql> show databases;ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.mysql>
  6. 登陆成功

    技术分享图片

假如安装设置的默认密码忘记了怎么办呢?在使用客户端连接服务端的时候需要经过认证,那么因为服务端也在自己的电脑上,所以只要绕过认证就可以了.

  1. 绕过服务端认证

    1. 进入 mysql 下 bin 目录

      cd /usr/local/mysql/bin/
    2. 获取超级权限

      sudo su
    3. 输入密码后输入

      ./mysqld_safe --skip-grant-tables &

      技术分享图片

    4. 打开另一个终端输入

      ./mysql
    5. 进入 mysql 输入

      flush privileges;
    6. 出现 Query OK, 输入,修改完成

      set password for root@localhost = password(‘password‘);

      技术分享图片

Windows 安装

Windows 安装分为两种,一种是有界面安装;一种是无界面安装.

有界面安装

安装和 MAC 差不多,选好自己需要的功能就可以了,默认是安装在c:\program files\mysql 下.关键记住自己设置的密码.

无界面安装

  1. 注意:5.7以后的版本安装成功后需要先初始化;

    mysqld --initialize-insecure
  2. 添加环境变量

    打开环境变量,将 MySQL 安装目录线的 bin 目录加入 path 变量;

  3. 将 mysqld 加入到 windows 系统服务

    mysqld --install

修改密码

  1. 修改默认密码需要先登陆成功,然后执行 update 语句直接修改 user 表中的密码;

    1. 5.7及以后的版本

      update mysql.user set authentication_string = password(‘root‘) where user = ‘root‘;
    2. 5.6及之前的版本

      update mysql.user set password = password(‘root‘) where user = ‘root‘;
  2. 不需要登录但需要知道旧密码

    mysqladmin -u root -p 旧密码 password 新密码
  3. 忘记登录密码

    其实思路和 mac 一样,都是需要绕过验证,然后登陆mysql 接着修改密码

    1. 启动服务器时,控制它不要加载授权表;

    2. 无密码登录服务器

    3. 执行sql 语句

      update mysql.user set authentication_string = password(‘root‘) where user = ‘root‘;
    4. 重启服务器.

用到的系统指令

  • mysqld 直接运行服务器程序;
  • mysqld --skip-grant-tables 跳过授权表,用于重设密码;
  • tasklist | findstr mysqld 找到 mysqld 服务进程;
  • taskkill /f /pid 结束服务器程序;
  • mysql -u 用户名 -p 密码 -h 主机 -P 端口号;
  • mysqld --install 将 mysqld 注册到 windows 服务中,在服务中叫 MySQL( 本质就是绑定了一个 exe 程序);
  • sc delete mysql 删除 windows 服务(重新 install 的话会显示服务已存在,需要重启);
  • exit 退出客户端

5.6和5.7的区别

  1. 5.7版本安装后需要初始化;

  2. 5.6游客模式 没有密码就可以登录但是无法操作数据,只能看到information_schema 和 mysql;

  3. 5.7中 data数据存放目录是由初始化时决定的

    1. 带界面的在 C:\ProgramData;
    2. 不带界面的在安装目录中和 bin 同级;

    5.6中 data 就在安装目录中

  4. 密码存储字段名,在5.6中为 password,5.7中为anthentication_string

SQL 语句

什么是 SQL

sql:结构化查询语言,是上个世纪70年代由 IBM 公司发明的一种专门检索,查询数据的编程语言,这种编程语言类似于脚本语言.它是一大堆的命令语句.只不过它执行的接口是 SQL 接口,它也提供了 SQL 的语句的解释器,比如 select,update 等命令,只不过这样的命令要比 bask 复杂一点.要向执行 SQL 的语句,需要有 SQL 模型才可以.首先需要把用户写的语句输送到服务器端,这就要服务器能够接受客户端的命令,并将命令所返回的结果,送回客户端.这就是 SQL 的执行环境,而这些语句,则是实现检索修改等相关的数据管理工作的.

所以 SQL 就是一种管理语言,用于管理关系型系统的,实现管理,修改数据等工作的,一种特殊语言解析器.

最开始是 IBM 提供的 SQL 数据接口( SEQUEL),但是 Oracle 也有自己的 SQL 数据接口,这就造成了规则不匹配.所以美国国家标准委员会,就定义了一个新标准: ANSI SQL 标准,它的发展历程:
  1. 上个世纪80年代,1986年研发出来,叫做 SQL-86标准;
  2. 89年扩展为 SQL-89;
  3. 1992年再次扩展, SQL-92:这一代被应用了很长的时间:各生产商 RDBMS 公司,要想实现上市,则必须严格的按照92的标准.但是这个标准定义的太严格,以至于几乎没有厂商可以达到这种标准,所以兼容的标准也分成了三中级别: Entry 级别, Intermediate 级别, Full 级别,几乎没有厂商可以达到 Full 级别,大部分都是 Entry 级别;
  4. 1999年再次扩展, SQL-99:MySQL 是完全兼容 SQL-99的 Entry 级别.而在此又出现了 Core SQL 级别;
  5. 2003年,又出现了 SQL-2003标准. XML 标准.

SQL 的版本就和 bash 一样,每一个更新版本都有新功能,而且执行速度,使用便捷,提供的扩展也不一样.

简单的 sql 语句

针对库的相关操作

    • create database 库名;
    • drop database 库名;
    • show databases;(查看所有数据库)
    • show create databases 库名;(查看建库语句)
    • alter database 库名 要修改的字段名;
    • alter database 库名 DEAFULT CHARACTER SET utf-8; (修改默认编码)
    • alter database 库名 CHARSET utf-8;

    注意在mysql 中 只能写 utf8

针对表的相关操作

  • 增:建表是首先要明确数据库

    • use 库名;
    • create table 表名(字段名 类型(长度),....);
    • create table 库名(name char(10),gender char(1), age int);
    • create table 库名.表名(字段名 类型(长度),...); # 创建同时指定数据库
    • drop table 表名;
    • show tables; 查看所有表
    • desc 表名; 查看表结构
    • show create table 表名; 查建表语句
    • alter table 表名 drop|change|modify|add
      • alter table 表名 drop 字段;
      • alter table 表名 change 旧字段名 新字段名 新类型;
      • alter table 表名 modify 字段名 新类型;
      • alter table 表名 add 字段名 类型;

    重命名表

    • rename table 旧表名 to 新表名;

    修改表的属性

    • alter table 表名 属性名 值;

针对记录的相关操作

    • insert into 表名 values(值1,值2...);
    • delete from 表名 where 字段名=值; # 没有符合条件的话删除全部数据
    • select * from 表名; # *表示通配符 查看所有字段
    • update 表名 set 字段名 = 新值 where 字段名 = 值; # 没有符合条件的话修改全部数据

命名规范

  1. 不能使用纯数字;
  2. 可以是数字、字母、下划线的组合;
  3. 可以用下划线开头;
  4. 不能使 sql 关键词,如 create;
  5. 不区分大小写。

修改默认配置

配置文件放在安装路径根目录中就是和 bin 同级,名称必须叫my.ini(mac 的不一样)

# 客户端的配置
[mysql]
user = root
password = password
default-character-set = utf8
# 服务端的配置
[mysqld]
character-set-server = utf8

MySQL

MySQL语句的执行过程

下面是 MySQL 的基本架构示意图,从中可以很清楚的看到 SQL 语句在 MySQL 的各个功能模块中的执行过程.

技术分享图片

大体来说, MySQL 可以分为 Server 层和存储引擎两部分.

Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数字和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。

而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MylSAM、Memory等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL5.5.5版本开始成为了默认存储引擎。

也就是说,你在执行 create table 建表的时候,如果不指定引擎类型,默认使用的就是 InnoDB。不过,可以通过指定存储引擎的类型来选择其他的引擎,比如在 create table 语句中使用 engine=memeory,来指定使用内存引擎创建表。不同存储引擎的表数据存取方式不同,支持的功能也不同。

从上图中可以看出,不同的存储引擎共用一个 Server 层,也就是从连接器到执行期的部分。

连接器

第一步,你会先连接到这个数据库上,这时候接待你的就是连接器。连接器负责跟客户端建立连接、获取权限、维持和馆里连接。这时候命令是这么写的:
mysql -h$ip -P$port -u$user -p
输完命令后,就需要在交互对话中输入密码。

连接命令中的 mysql 是客户端工具,用来根服务端建立连接。在完成经典的 TCP 握手后,连接器就开始认证身份,这个时候用的就是你输入的用户名和密码。
  • 如果用户名或密码不对,会返回‘Access denied for user‘的错误,然后客户端程序结束。

  • 如果用户名密码认证通过,连接器会到权限表里面查看用户拥有的权限。之后,这个链接里面的权限判断逻辑,都依赖于此时读到的权限。这意味着修改权限不会立马有效,需要重新连接服务器才会生效。

    连接完成后,如果没有后续的动作,这个链接就处于空闲状态,你可以在 show processlist 命令中看到它。如下所示,其中的 Command 列显示为Query,表示现在系统里面有一个查询链接。

技术分享图片

客户端如果太长时间不活跃,连接器就会自动断开连接。这个时间由参数 wiait_timeout 控制,默认为8小时。

如果连接断开,客户端再次发送请求时,会收到错误提醒:Lost connection to MySQL server during query。这时候如果要继续连接,就需要重连,然后执行查询。

数据库里面,长连接是指连接成功后,如果客户端持续有请求,则一直使用同一个连接。短连接则是指每次执行完很少的几次查询就断开连接,下次查询重建一个。

建立连接的过程通常是比较复杂的,所以在使用中尽量减少建立连接的动作,也就是尽量使用长连接。

但是全部使用长连接后,会发现 MySQL 占用内存涨的特别快,这是因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的。这些资源会在连接断开才会释放,所以如果大量的长连接积累的话,会导致内存占用太大,被系统强行杀掉(OOM),从现象看就是 MySQL 异常重启了。

怎么解决这个问题呢?有两种方案。
  1. 定期断开长连接。使用一段时间,或者程序里面判断执行过占用内存的大查询后,断开连接,之后要查询再连接。
  2. 如果使用的是5.7及以后的版本,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接回复到刚刚创建完时的状态。

查询缓存

连接建立完成后,你就可以执行 select 语句了。执行逻辑就会来到第二步:查询缓存。

MySQL 拿到一个查询请求后,会先到查询内存查看,之前是否执行过这条语句。之前执行过的语句及其结果可能会以 key-value 的形式存储在内存中。key 是查询的语句,value 是查询的结果。如果你的查询能够直接在这个缓存中找到 key,那么这个 value 就会直接返回给客户端。

如果之前没有执行过这条语句,就会执行后面的执行阶段。执行完成后,执行结果会存入查询缓存。这样的优点是,如果查询缓存命中,不需要执行后面的复杂操作,就可以直接返回结果,效率会极大地提高。

**但是大多数情况不建议使用查询缓存,因为查询缓存往往利大于弊。**

查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。因此很可能费劲存储的缓存,还没使用就被一个更新全清空了。对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非所有的业务是一张静态表,很长时间更新一次。比如一个系统配置表,那这张表上的查询才适合使用查询缓存。

好在 MySQL 提供了按需使用的方式。可以将参数query_cache_type 设置成 DEMAND,这样对于默认的 SQL 语句都不使用查询缓存。而对于你确定要使用查询缓存的语句,可以用 SQL_CACHE 显示指定,像下面这个语句一样:
mysql> select SQL_CACHE * from T where ID=10;
不过在最新的8.0版本这功能被删了。

分析器

如果没有命中查询缓存,就要开始真正的执行语句了。首先,MySQL 需要知道你要做什么,因此需要对 SQL 语句做解析。

分析器首先会做‘’词法分析‘’,你输入的是由多个字符串和空格组成的一条 SQL 语句,MySQL需要识别出里面的字符串分别是什么,代表什么。

MySQL 从你输入的‘’select‘’这个关键词识别出来,这是一个查询语句。它也要把字符串‘’T‘’识别成‘’表名T‘’,把字符串‘’ID‘’识别成‘’列 ID‘’。

做完了这些识别以后,就要做‘’语法分析‘’。根据此法分析的结果,语法分析器会根据语法规则,判断你输入的这个 SQL 语句是否满足 MySQL 语法。

如果你的语句不对,就会收到‘’You have an error in your SQL syntax‘’的错误提醒。

一般语法错误会提示第一个出现错误的位置,所以你要关注的是紧接‘’use near‘’的内容。

优化器

经过了分析器,MySQL 就知道要做什么了。在开始执行之前,还要经过优化器的处理。

优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。比如下面这个语句,是执行两个表的 join:
mysql> select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
  • 既可以先从表 t1中取出 c=10 记录的ID 值,在根据 ID 值关联到表 t2,再判断 t2里面 d 的值是否等于20。

  • 也可以先从表 t2里面取出 d=20记录的 ID 值,在根据 ID 值关联到 t1,再判断 t1里面 c 的值是否等于10。

    这两种执行方案的逻辑结果是一样的,但是效率会有不同,而优化器的作用就是决定选择使用哪个方案。

    优化器阶段完成后,这个语句的执行方案就确定下来了,然后进入执行器阶段。

执行器

MySQL 通过分析器知道了要做什么,通过了优化器知道怎么做,于是就进入了执行器阶段,开始执行语句。

开始执行的时候,需要先判断用户对表 T 是否拥有查询权限,如果没有,就会返回没有权限的错误。
mysql> select * from T where ID=10;
ERROR 1142 (42000): SELECT command denied to user ‘b‘@‘localhost‘ for table ‘T‘
如果有权限,就打开表继续执行。打开表的时候,执行器会根据表的引擎定义,去使用该引擎提供的接口。

比如表 T 中,ID 字段么有索引,那么执行期的执行流程是这样的:
  1. 调用 InnoDB 引擎接口取该表的第一行,判断 ID 值是否为10,如果不是则跳过,如果是则将这行存在结果集中;

  2. 调用引擎接口取‘’下一行‘’,重复相同的判断逻辑,直到取到这个表的最后一行。

  3. 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

    至此,该语句执行结束。

    对于有索引的表,执行的逻辑差不多。第一次调用的是‘’取满足条件的第一行‘’这个接口,之后循环取‘’满足条件的下一行‘’这个接口,这些接口都是引擎中已经定义好的。

    你会在数据库的慢查询日志中看到一个 rows_examined 的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。

    在某些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟rows_examined 并不是完全相同的。

数据库(一)

标签:pca   show   没事   结束   匹配   体系结构   ogr   国家标准   连接服务器   

原文地址:https://www.cnblogs.com/zuanzuan/p/9986456.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!