SQLite3 数据库学习(一):数据库和 SQLite 基础

参考引用

  • SQL 必知必会
  • SQLite 权威指南(第二版)
  • 关系型数据库概述

1. 数据库基础

1.1 什么是数据库

  • 数据库(database):保存有组织的数据的容器(通常是一个文件或一组文件)

    • 可以将其想象为一个文件柜,此文件柜是一个存放数据的物理位置,不管数据是什么以及如何组织的
  • 数据库软件应称为 DBMS(数据库管理系统),数据库是通过 DBMS 创建和操纵的容器

    • 在很大程度上说,数据库究竟是文件还是别的什么东西并不重要,因为你并不直接访问数据库,而是使用 DBMS,它替你访问数据库

1.2 为什么需要数据库?

因为应用程序需要保存用户的数据,比如 Word 需要把用户文档保存起来,以便下次继续编辑或者拷贝到另一台电脑。要保存用户的数据,一个最简单的方法是把用户数据写入文件

  • 但是,随着应用程序的功能越来越复杂,数据量越来越大,如何管理这些数据就成了大问题

    • 读写文件并解析出数据需要大量重复代码
    • 从成千上万的数据中快速查询出指定数据需要复杂的逻辑

    如果每个应用程序都各自写自己的读写数据的代码,一方面效率低,容易出错,另一方面,每个应用程序访问数据的接口都不相同,数据难以复用

  • 所以,数据库作为一种专门管理数据的软件就出现了。应用程序不需要自己管理数据,而是通过数据库软件提供的接口来读写数据。至于数据本身如何存储到文件,那是数据库软件的事情,应用程序自己并不关心

1.3 基本概念

1.3.1 表
  • 表(table):某种特定类型数据的结构化清单

    • 在你将资料放入自己的文件柜时,并不是随便将它们扔进某个抽屉就完事了,而是在文件柜中创建文件,然后将相关的资料放入特定的文件中
    • 在数据库领域中,这种文件称为表。表可以保存顾客清单、产品目录,或者其他信息清单
    • 存储在表中的数据是同一种类型的数据或一个清单
      • 不应该将顾客的清单与订单的清单存储在同一个数据库表中,因为这样做将使以后的检索和访问很困难,应该创建两个表,每个清单一个表
  • 表名

    • 数据库中的每个表都有一个名字,用来标识自己
    • 此名字是唯一的,这表示数据库中没有其他表具有相同的名字,表名的唯一性取决于多个因素,如数据库名和表名等的结合,这表示在不同的数据库中可以使用相同的表名
  • 模式(schema):关于数据库和表的布局及特性的信息

    • 这些特性定义了数据在表中如何存储,如:可以存储什么样的数据,数据如何分解,各部分信息如何命名等
1.3.2 列和数据类型
  • 列(column):表中的一个字段,所有表都是由一个或多个列组成的

    • 理解列的最好办法是将数据库表想象为一个网格,网格中每一列存储着一条特定的信息
    • 例如,在顾客表中,一个列存储着顾客编号,另一个列存储着顾客名
  • 数据类型(datatype):所容许的数据的类型

    • 每个表列都有相应的数据类型,它限制(或容许)该列中存储的数据种类
      • 例如,可以防止在数值字段中录入字符值
    • 数据类型还可帮助正确地排序数据,并在优化磁盘使用方面起到重要作用
1.3.3 行
  • 行(row):表中的一个记录
    • 表中的数据是按行存储的,所保存的每个记录存储在自己的行内
    • 例如,顾客表可以每行存储一个顾客,表中的行数为记录的总数
1.3.4 键
1、主键
  • 在关系型数据库中,一张表中的每一行数据被称为一条记录
    • 一条记录就是由多个字段组成的。例如,下表 students 的两行记录

在这里插入图片描述

  • 主键(primary key):一列(或一组列),其值能够唯一区分表中每个行

    • 能够通过某个字段唯一区分出不同的记录,这个字段被称为主键
    • 例如,假设上表把 name 字段作为主键,那么通过名字小明或小红就能唯一确定一条记录
  • 业务场景中选取主键的一个基本原则是:不使用任何业务相关的字段作为主键。作为主键最好是完全业务无关的字段,一般把这个字段命名为 id,常见的可作为 id 字段的类型有:

    • 自增整数类型:数据库会在插入数据时自动为每一条记录分配一个自增整数,这样就完全不用担心主键重复,也不用自己预先生成主键
    • 全局唯一 GUID 类型:使用一种全局唯一的字符串作为主键,类似8f55d96b-8acc-4636-8cb8-76bf8abc2f57。GUID 算法通过网卡 MAC 地址、时间戳和随机数保证任意计算机在任意时间生成的字符串都是不同的
    • 每个行都必须具有一个主键值(主键列不允许 NULL 值)

    通常,自增类型的主键就能满足需求。上表 students 中定义的主键也是 BIGINT NOT NULL AUTO_INCREMENT 类型

2、联合主键

在这里插入图片描述

  • 关系型数据库还允许通过多个字段唯一标识记录,即两个或更多的字段都设置为主键,这种主键被称为联合主键

    • 对于联合主键,允许一列有重复,只要不是所有主键列都重复即可
  • 如果把上表的 id_num 和 id_type 这两列作为联合主键,那么上面的 3 条记录都是允许的,因为没有两列主键组合起来是相同的

    • 没有必要的情况下,尽量不使用联合主键,因为它给关系表带来了复杂度的上升

主键的最好习惯

  • 不更新主键列中的值
  • 不重用主键列的值
  • 不在主键列中使用可能会更改的值
3、外键
一对多
  • 当用主键唯一标识记录时,就可以在 students 表中确定任意一个学生的记录

在这里插入图片描述

  • 还可以在 classes 表中确定任意一个班级记录

在这里插入图片描述

  • 但是如何确定 students 表的一条记录,例如,id=1 的小明,属于哪个班级呢?
    • 由于一个班级可以有多个学生,在关系模型中,这两个表的关系可以称为 “一对多”,即一个 classes 的记录可以对应多个 students 表的记录
    • 为了表达这种一对多的关系,需要在 students 表中加入一列 class_id,让它的值与 classes 表的某条记录相对应
    • 在 students 表中,通过 class_id 的字段,可以把数据与另一张表关联起来,这种列称为外键 (下图红框列)

在这里插入图片描述

  • 这样,就可以根据 class_id 这个列直接定位出一个 students 表的记录应该对应到 classes 的哪条记录

    • 小明的 class_id 是 1,因此,对应的 classes 表的记录是 id=1 的一班
    • 小红的 class_id 是 1,因此,对应的 classes 表的记录是 id=1 的一班
    • 小白的 class_id 是 2,因此,对应的 classes 表的记录是 id=2 的二班
  • 外键并不是通过列名实现的,而是通过定义外键约束实现的

    ALTER TABLE students
    ADD CONSTRAINT fk_class_id    // 外键约束名称,可随意指定
    FOREIGN KEY (class_id)        // 指定 class_id 作为外键
    REFERENCES classes (id)       // 指定这个外键将关联到 classes 表的 id 列(即 classes 表的主键)
    DROP FOREIGN KEY fk_class_id  // 删除外键约束 fk_class_id,删除外键约束并没有删除外键这一列
    
多对多
  • 通过一个表的外键关联到另一个表,可以定义出一对多关系。有些时候,还需要定义 “多对多” 关系。例如,一个老师可以对应多个班级,一个班级也可以对应多个老师,因此,班级表和老师表存在多对多关系
    • 多对多关系是通过两个一对多关系实现的,即通过一个中间表,关联两个一对多关系,就形成了多对多关系

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 通过中间表 teacher_class 可知 teachersclasses 的关系

    • id=1 的张老师对应 id=1,2 的一班和二班
    • id=2 的王老师对应 id=1,2 的一班和二班
    • id=3 的李老师对应 id=1 的一班
    • id=4 的赵老师对应 id=2 的二班
  • 同理可知 classesteachers 的关系

    • id=1 的一班对应 id=1,2,3 的张老师、王老师和李老师
    • id=2 的二班对应 id=1,2,4 的张老师、王老师和赵老师
一对一
  • 一个表的记录对应到另一个表的唯一一个记录
    • 例如,students 表的每个学生可以有自己的联系方式,如果把联系方式存入另一个表 contacts,就可以得到一个 “一对一” 关系
    • 实际上,一对一关系准确地说,是 contacts 表一对一对应 students 表

在这里插入图片描述

  • 还有一些应用会把一个大表拆成两个一对一的表,目的是把经常读取和不经常读取的字段分开,以获得更高的性能
    • 例如,把一个大的用户表拆分为用户基本信息表 user_info 和用户详细信息表 user_profiles,大部分时候,只需要查询 user_info 表,并不需要查询 user_profiles 表,这样就提高了查询速度
1.3.5 索引
  • 在关系数据库中,如果有上万甚至上亿条记录,在查找记录的时候,想要获得非常快的速度,就需要使用索引

    • 索引是关系数据库中对某一列或多个列的值进行预排序的数据结构
    • 通过使用索引,可以让数据库系统不必扫描整个表,而是直接定位到符合条件的记录,这就大大加快了查询速度
  • 例如,对于 students 表,如果要经常根据 score 列进行查询,就可以对 score 列创建索引

    ALTER TABLE students
    ADD INDEX idx_score (score);
    //ADD INDEX idx_name_score (name, score);  // 索引名称是任意的,索引如果有多列,可以在括号里依次写上
    

在这里插入图片描述

唯一索引
  • 在设计关系数据表的时候,看上去唯一的列,例如身份证号、邮箱地址等,因为他们具有业务含义,因此不宜作为主键。但是,这些列根据业务要求,又具有唯一性约束:即不能出现两条记录存储了同一个身份证号。这个时候,就可以给该列添加一个唯一索引。例如,假设 students 表的 name 不能重复
    ALTER TABLE students
    ADD UNIQUE INDEX uni_name (name);  // 通过 UNIQUE 关键字就添加了一个唯一索引
    

1.4 数据模型

1.4.1 层次模型
  • 层次模型就是以 “上下级” 的层次关系来组织数据的一种方式,层次模型的数据结构看起来就像一颗树

在这里插入图片描述

1.4.2 网状模型
  • 网状模型把每个数据节点和其他很多节点都连接起来,它的数据结构看起来就像很多城市之间的路网

在这里插入图片描述

1.4.3 关系模型
  • 关系模型把数据看作是一个二维表格,任何数据都可以通过行号 + 列号来唯一确定,它的数据模型看起来就是一个 Excel 表
    • 基于关系模型的关系型数据库成为主流,因为相比层次模型和网状模型,关系模型理解和使用起来最简单

在这里插入图片描述

  • 现有主流的关系型数据库
    • 商用数据库,例如:Oracle,SQL Server,DB2 等
    • 开源数据库,例如:MySQL,PostgreSQL 等
    • 桌面数据库,以微软 Access 为代表,适合桌面应用程序使用
    • 嵌入式数据库,以 SQLite 为代表,适合手机应用和桌面程序

1.5 数据类型

  • 通常来说,BIGINT 能满足整数存储的需求,VARCHAR(N) 能满足字符串存储的需求,这两种类型是使用最广泛的
    • 下表中列举了最常用的数据类型,各数据库厂商还会支持特定的数据类型,例如 JSON
      在这里插入图片描述

2. SQL 介绍

  • SQL(发音为字母 S-Q-L 或 sequel)是结构化查询语言(Structured Query Language)的缩写

    • SQL 是一种专门用来与数据库通信的语言
  • SQL 的优点

    • SQL不是某个特定数据库供应商专有的语言
      • 几乎所有重要的 DBMS 都支持 SQL
    • SQL 简单易学
      • 它的语句全都是由描述性很强的英语单词组成,而且这些单词的数目不多
    • SQL 是一种强有力的语言,灵活使用其语言元素,可以进行非常复杂和高级的数据库操作
  • SQL 语言定义 3 种操作数据库的能力

    • DDL:Data Definition Language
      • DDL 允许用户定义数据,也就是创建表、删除表、修改表结构这些操作
      • 通常,DDL 由数据库管理员执行
    • DML:Data Manipulation Language
      • DML 为用户提供添加、删除、更新数据的能力,这些是应用程序对数据库的日常操作
    • DQL:Data Query Language
      • DQL 允许用户查询数据,这也是通常最频繁的数据库日常操作

任意两个 DBMS(数据库管理系统)实现的 SQL 都不完全相同,无法完全直接移植

3. SQLite 介绍

3.1 简介

  • SQLite 是一款开源的、嵌入式关系型数据库

    • 它没有独立运行的进程,它与所服务的应用程序在应用程序进程空间内共生共存
    • 它的代码与应用程序代码也是在一起的,或者说嵌入其中作为托管它的程序的一部分
    • 程序只需要做自己的事,管理自己的数据,不需要详细了解 SQLite 是如何工作的
  • 数据库服务器和客户端运行在同一个进程中的好处是:不需要网络配置或管理

    • 不用担心防火墙或者地址解析,不用浪费时间管理复杂的授权和权限
    • 可以减少网络调用相关的消耗,简化数据库管理,使程序更容易部署
  • 从下图可知,一个 Perl 脚本、一个标准 C/C++ 程序和一个 Apache 托管的 PHP 脚本都使用 SQLite

    • 这三种都有嵌入在它们进程空间的 SQLite,这样做不仅可以使这些进程运行各自的代码,也可以成为独立的数据库服务器
    • 此外,尽管每个进程中都有独立的数据库服务器,但它们依然可以操作同一个数据库文件,因为 SQLite 利用操作系统功能来完成数据的同步和加锁

在这里插入图片描述

3.2 体系结构

在这里插入图片描述

  • 接口

    • 接口处于栈的顶端,由 SQLite C API 组成
    • 程序、脚本语言还有与 SQLite 交互的库文件最终都是通过它与 SQLite 交互的
  • 编译器

    • 编译过程从词法分析器 (Tokenizer) 和语法分析器 (Parser) 开始。它们协同处理文本形式的结构化查询语句 (Structured Query Language,SQL),分析其语法有效性,然后转化为底层能更方便处理的层次化数据结构
    • SQLite 词法分析器是手动编码实现,它的语法分析器是由 SQLite 特定的语法分析生成器 Lemon 产生
  • 虚拟机

    • 架构栈的中心部分是虚拟机,也叫做虚拟数据库引 (Virtual DataBase Engine,VDEB)
    • VDBE 是 SQLite 的核心,它之前的所有模块都是用于创建 VDBE 程序的,它之后的所有模块都是用于执行 VDBE 序的,每次执行一条指令
  • 后端

    • 后端由 B-tree、页缓存 (page cache) 以及操作系统接口组成
    • B-tree 将页面组织成树状结构,这种组织结构很适合搜索,页面就是树的叶子
    • pager (SQLite 的一种数据结构) 帮助 B-tree 管理页面,它负责传输

3.3 性能和局限性

3.3.1 性能
  • 在对单表进行查询时平均而言,SQLite 与其他数据库一样快。简单的 SELECT、INSERT 和 UPDATE 是相当快速的。SQLite 通常要快其他数据库,因为它在处理一个事务开始,或者一个查询计划的产生方面开销较小,并且没有调用服务器的网络或认证以及权限协商的开销
  • 但是随着查询变大变复杂,查询时间使得网络调用或者事务处理开销相形见绌,SQLite 将会与其他数据库一样,这时一些大型的设计复杂的数据库开始发挥作用了
3.3.2 局限性
  • 并发
    • SQLite 的锁机制是粗粒度的,它允许多个读,但是一次只允许一个写
    • 写锁会在写期间排他地锁定数据库,其他人在此期间不能访问数据库
  • 网络
    • 虽然 SQLite 数据库可以通过网络文件系统共享,但是与这种文件系统相关的潜在延时会导致性能受损
    • 如果文件系统的锁实现不当,可能允许两个客户端同时修改同一个数据库文件,这必然会导致数据库出错

并发性要求低、数据小于 1TB、本地存储的应用场景下可以考虑使用 SQLite

3.4 SQLite 安装

3.4.1 SQLite on Windows

  • Qt 编译安装 SQLite
  1. 源码下载
    在这里插入图片描述

  2. 在 Qt 中新建 C 项目
    在这里插入图片描述

  3. 将第 1 步下载的源码解压后全部拷贝到第 2 步中创建的 C 项目中(与 main.c 同级),并删除原有 main.c 文件(因为源码 shell.c 中也有 main 函数,会产生冲突
    在这里插入图片描述

  4. 勾选下图所示选项
    在这里插入图片描述

  5. 编译成功如下
    在这里插入图片描述

  • 安装数据库查看工具 Sqlite Expert
    • Sqlite Expert

3.4.2 SQLite on Linux

  • 安装 SQLite

    $ sudo apt-get install sqlite3
    
  • 运行 SQLite
    在这里插入图片描述

  • 安装数据库查看工具 SQLite Browser

    $ sudo apt install sqlitebrowser -y
    

linux 下通过 gcc 编译 sqlite3

  • gcc -o sqlite3 sqlite3.c shell.c -lpthread -ldl

linux下通过arm-linux-gcc交叉编译sqlite3

  • arm-linux-gcc -o sqlite3 sqlite3.c shell.c -lpthread -ldl

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/147069.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea查看UML类图

idea查看UML类图 一、如何查看UML类图 1.1 选择需要查看的类或者包,鼠标右键,选择Diagrams->Show Diagram 1.2 对于UML类图中的包,选中后点击鼠标右键-> Expand Nodes(展开节点) 展开前 展开后 1.3 展开后分布比较凌乱&#xff…

带你快速掌握Linux最常用的命令(图文详解)- 最新版(面试笔试常考)

最常用的Linux指令(图文详解)- 最新版 ls:列出目录中的文件和子目录。(重点)cd:改变当前工作目录。绝对路径:相对路径 pwd:显示当前工作目录的路径。mkdir:创建一个新的目…

教你轻松解决win系统ucrtbased.dll丢失的问题,亲测有效!

ucrtbased.dll是一个动态链接库文件(DLL),它是Windows操作系统中的一部分,主要负责提供操作系统和应用程序所需的函数和接口。这个文件包含了操作系统和应用程序共同使用的通用代码,以确保不同程序之间的兼容性和稳定性…

6.2 List和Set接口

1. List接口 List接口继承自Collection接口,List接口实例中允许存储重复的元素,所有的元素以线性方式进行存储。在程序中可以通过索引访问List接口实例中存储的元素。另外,List接口实例中存储的元素是有序的,即元素的存入顺序和取…

C语言之for while语句详解

C语言之for while语句详解 文章目录 C语言之for while语句详解简介1 while语句1.1while语句的格式1.2 while语句的实践 2 for2.1 for语句格式2.2 for循环的实践 3 do while3.1 do while语句格式3.2 do while循环的实践 3 循环中break和continue3.1 while语句中的break和continu…

编写程序,要求输入x的值,输出y的值。分别用(1)不嵌套的if语句(2)嵌套的if语句(3)if-else语句(4)switch语句。

编写程序,要求输入x的值,输出y的值。分别用(1)不嵌套的if语句(2)嵌套的if语句(3)if-else语句(4)switch语句。 选择结构是编程语言中常用的一种控制结构&…

长短期记忆(LSTM)与RNN的比较:突破性的序列训练技术

长短期记忆(Long short-term memory, LSTM)是一种特殊的RNN,主要是为了解决长序列训练过程中的梯度消失和梯度爆炸问题。简单来说,就是相比普通的RNN,LSTM能够在更长的序列中有更好的表现。 Why LSTM提出的动机是为了解…

django理解02 前后端分离中的问题

前后端分离相对于传统方式的问题 前后端数据交换的问题跨域问题 页面js往自身程序(django服务)发送请求,这是浏览器默认接受响应 而请求其它地方是浏览器认为存在潜在危险。自动隔离请求!!! 跨域问题的解决…

springcloud整合nacos实现服务注册

Nacos是一个开源的分布式系统服务和基础设施解决方案,用于实现动态服务发现、配置管理和服务治理。它可以帮助开发人员和运维团队更好地管理微服务架构中的服务实例、配置信息和服务调用。 Nacos提供了服务注册与发现、动态配置管理、服务路由和负载均衡等功能&…

C++之set/multise容器

C之set/multise容器 set基本概念 set构造和赋值 #include <iostream> #include<set> using namespace std;void PrintfSet(set<int>&s) {for(set<int>::iterator it s.begin();it ! s.end();it){cout<<*it<<" ";}cout&l…

typora使用PicGo自动上传图片到chevereto图床

typora使用PicGo自动上传图片到chevereto图床 近期发现&#xff0c;gitee图床不能用了。github又涉及科学上网。搜索了开源图床方案&#xff0c;找到了chevereto&#xff0c;使用起来还不错。分享给大家。 文章目录 typora使用PicGo自动上传图片到chevereto图床chevereto图床安…

精密云工程:智能激活业务速率 ——华为云11.11联合大促倒计时 仅剩3日

现新客3.96元起&#xff0c;下单有机会抽HUAWEI P60 Art&#xff0c;福利仅限双十一&#xff0c;机会唾手可得&#xff0c;立即行动&#xff01; 双十一购物节来临倒计时&#xff0c;华为云备上多款增值产品&#xff0c;以最优品质迸发冬日技术热浪&#xff0c;满足行业技术应用…

Mac 安装 protobuf 和Android Studio 使用

1. 安装,执行命令 brew install protoc 2. Mac 错误提示&#xff1a;zsh: command not found: brew解决方法 解决方法&#xff1a;mac 安装homebrew&#xff0c; 用以下命令安装&#xff0c;序列号选择中科大&#xff08;1&#xff09;或 阿里云 /bin/zsh -c "$(curl…

MLC-LLM 支持RWKV-5推理以及对RWKV-5的一些思考

自从2023年3月左右&#xff0c;chatgpt火热起来之后&#xff0c;我把关注的一些知乎帖子都记录到了这个markdown里面&#xff0c;&#xff1a;https://github.com/BBuf/how-to-optim-algorithm-in-cuda/tree/master/large-language-model-note &#xff0c;从2023年3月左右到现…

安装插件时Vscode XHR Failed 报错ERR_CERT_AUTHORITY_INVALID

安装插件时Vscode XHR Failed 报错ERR_CERT_AUTHORITY_INVALID 今天用vscode 安装python插件时报XHR failed,无法拉取应用商城的数据&#xff0c; 报的错如下&#xff1a; ERR_CERT_AUTHORITY_INVALID 翻译过来就是证书有问题 找错误代码的方法&#xff1a; 打开vscode, 按F1…

Swift 如何打造兼容新老系统的字符串分割(split)方法

0. 概览 在 Swift 的开发中&#xff0c;我们经常要与字符串打交道。其中一个常见的操作就是用特定的“分隔符”来分割字符串&#xff0c;这里分隔符可能不仅仅是字符&#xff0c;而是多字符组成的字符串。 从 iOS 16 开始&#xff0c; 新增了对应的方法来专注此事。不过&am…

HBase中的数据表是如何用CHAT进行分区的?

问CHA&#xff1a;HBase中的数据表是如何进行分区的&#xff1f; CHAT回复&#xff1a; 在HBase中&#xff0c;数据表是水平分区的。每一个分区被称为一个region。当一个region达到给定的大小限制时&#xff0c;它会被分裂成两个新的region。 因此&#xff0c;随着数据量的增…

mac苹果笔记本应用程序在哪?有什么快捷方式吗?

苹果笔记本电脑一直以来都被广泛使用&#xff0c;而苹果的操作系统 macOS 也非常受欢迎。一台好的笔记本电脑不仅仅依赖于硬件配置&#xff0c;还需要丰富多样的应用程序来满足用户的需求。苹果笔记本应用程序在哪&#xff0c;不少mac新手用户会有这个疑问。在这篇文章中&#…

2023.11.14 hivesql的容器,数组与映射

目录 https://blog.csdn.net/m0_49956154/article/details/134365327?spm1001.2014.3001.5501https://blog.csdn.net/m0_49956154/article/details/134365327?spm1001.2014.3001.5501 8.hive的复杂类型 9.array类型: 又叫数组类型,存储同类型的单数据的集合 10.struct类型…

Selenium操作已经打开的Chrome浏览器窗口

Selenium操作已经打开的Chrome浏览器窗口 0. 背景 在使用之前的代码通过selenium操作Chrome浏览器时&#xff0c;每次都要新打开一个窗口&#xff0c;觉得麻烦&#xff0c;所以尝试使用 Selenium 获取已经打开的浏览器窗口&#xff0c;在此记录下过程 本文使用 chrome浏览器来…