嵌入式数据库是什么区块链数据管理工具(嵌入式数据库是什么)

SQLite,是一款轻型的数据库,其设计目标是嵌入式的数据库,而且当前在很多嵌入式产品中使用到了sqlite数据库,sqlite数据库占用资源非常的低,对嵌入式设备而言,内存是非常宝贵的,而sqlite数据库可能只需要几百K的内存就够了。

Sqlite数据库还能够支持Windows/Linux/Unix等等主流的操作系统,其跨平台的可移植性特别强,这极大的拓展了其生存的空间。

同时能够跟很多程序语言相结合,比如C#、PHP、Java,C等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快,比起Oracle数据库来说,免费也是极我爱线报网每日持续更新海量各大内部创业教程大的优势。

SQLite第一个Alpha版本诞生于2000年5月,至2018年已经有18个年头, SQLite 3也已经发布,并成功的进入了我们的事业。

除了上面提到的低内存占用率、跨平台可移植性、多语言支持、免费开源,sqlite3数据库还有强大的功能,比如支持数据库大小可达2TB,十多万行的代码非常适合学习,良好的代码注释等等。

那么我们学习数据库好可以快速的入门,在门外徘徊太久的话会挫伤我们学习的积极性。如果你是一个嵌入式的学习和开发者,那么从以下两个方面出发可以帮你快速的上手sqlite3数据库:

1、Sqlite3的命令 :数据库的创建及增删改查

2、2、sqlite3 API函数接口:用AP我爱线报网每日持续更新海量各大内部创业教程I接口实现数据库的创建及增删改查

当然了,以下是基于Ubuntu平台做的测试:

1– 安装数据库:

在线安装:sudo apt-get install sqlite sqlite3

sudo apt-get install libsqlite3-dev

sudo apt-get install sqlitebrowser

离线安装:

下载安装下面三个包:

libsqlite3-0_3.7.2-1ubuntu0.1_i386.deb

libsqlite3-dev_3.7.2-1ubuntu0.1_i386.deb

sqlite3_3.7.2-1ubuntu0.1_i386.deb

sudo dpkg -i *.de我爱线报网每日持续更新海量各大内部创业教程b (数据库安装文件)

2、Sqlite3的命令

2.1、创建数据库

sqlite3 stu.db

必须指定数据库名字

2.2、sqlite命令

系统命令 以 “.”开头

普通命令 ,以”;”结束

.schema 查看表的结构

.quit 退出数据库

.exit 退出数据库

.help 查看帮助信息

.databases 查看数据库

.tables 显示数据库中所有的表的表名

2.3、sqlite3 的使用 : 增删改查

1– 创建一张表

create table 表名(字段名称1 字段类型,字段名称2 字段类型, ….);

create table stu(id int, name char, sex char , s我爱线报网每日持续更新海量各大内部创业教程core int);

2– 向表中插入一条记录

insert into 表名 values (字段值1,字段值2,…);

insert into stu values(1001, zhangsan, m, 89);

insert into stu (id, name, sex,score) values(1002, lisi, m, 99);

3– 查询记录

select * from stu; // 查找所有的记录

select * from stu where id=1001; // 查找符号条件的记录

select * from stu where id=1001 and name=zhangs我爱线报网每日持续更新海量各大内部创业教程an; // 字符串需要加引号

select * from stu where name = zhangsan or score=92;

4– 删除记录

delete from stu where id=1004;

5– 更新记录

update stu set score=98 where id=1003;

6– 删除一张表

drop table stu;

7– 添加一列

alter table stu add column score int;

8– 删除一列

sqlite3 不允许直接删除一列

1)先创建一张新表

create table stu1 as select id , name from stu我爱线报网每日持续更新海量各大内部创业教程;

2)删除原来的旧表

drop table stu;

3)对新表重命名

alter table stu1 rename to stu;

9– 数据库主键(既设置的数据将会是唯一存在的)

create table usr(name text primary key , passwd text);

3、sqlite3 API 函数接口:

学习API函数接口,那么首先要掌握函数接口的三要素: 功能–参数–返回值,

然后就是写代码去验证我们队函数的理解,然后将函数用到实际的项目开发当中

(1)int sqlite3_open(

const char *filename, /* Database filename (我爱线报网每日持续更新海量各大内部创业教程UTF-8) */

sqlite3 **ppDb /* OUT: SQLite db handle */

);

功能:打开一个数据库

参数:filename 数据库名字

ppdb 操作数据库的指针,句柄。

返回值:成功 SQLITE_OK , 失败 error_code

(2)const char *sqlite3_errmsg(sqlite3* db);

功能:获取错误信息描述

(3)int sqlite3_close(sqlite3* db);

功能:关闭一个数据库

(4)int sqlite3_exec(

sqlite3* db, /* An open database */

const char *sql, /我爱线报网每日持续更新海量各大内部创业教程* SQL to be evaluated */

int (*callback)(void*,int,char**,char**), /* Callback function */

void * arg, /* 1st argument to callback */

char **errmsg /* Error msg written here */

);

功能:执行一条sql语句

参数:db 数据库的句柄指针

sql 将要被执行sql语句

callback 回调函数, 只有在查询语句时,才给回调函数传参

arg 为callback 传参的

errmsg 错误信息的地址

返回值:成功 SQLITE_OK

出错 err我爱线报网每日持续更新海量各大内部创业教程code 错误码

int (*callback)(void* arg ,int ncolumn ,char** f_value,char** f_name)

功能:得到查询结果

参数:arg 为回调函数传递参数使用的

ncolumn 记录中包含的字段的数目

f_value 包含每个字段值的指针数组

f_name 包含每个字段名称的指针数组

返回值:成功 0,出错 非0

(5)int sqlite3_get_table(

sqlite3 *db, /* An open database */

const char *zSql, /* SQL to be evaluated */

char ***pazResult, 我爱线报网每日持续更新海量各大内部创业教程/* Results of the query */

int *pnRow, /* Number of result rows written here */

int *pnColumn, /* Number of result columns written here */

char **pzErrmsg /* Error msg written here */

);

功能:查询数据库,它会创建一个新的内存区域来存放查询的结果信息

参数:db 数据库操作句柄

sql 数据库的sql语句

azResult 查询的结果

nRow 行数

nColumn 列数

errmsg 错误消息

返回值:

成功 0

出错 errcode

n我爱线报网每日持续更新海量各大内部创业教程row的值为查询到的符合条件的记录数(不包括字段名)。

ncolumn的值为查询到的符合条件的字段数。

注意:nrow的值不包括字段名,如果打印时用for (i = 0; i < nrow; i++)会打印出字段名,但是会少打印出一条符合条件的记录。

因此打印时要用 for (i = 0; i

(6)void sqlite3_free_table(char **result);

功能:释放内存

4、下面我们先来测一下sqlite命令的使用:

fengjunhui@ubuntu:~/Sqlite$ sqlite3 fengjunhui.db

SQLite version 3.7.2

Enter “.help” f我爱线报网每日持续更新海量各大内部创业教程or instructions

Enter SQL statements terminated with a “;”

sqlite> create table stu(id int,name char,sex char,score int);

sqlite> insert into stu values(1001,fengjunhui,m,88);

1001|fengjunhui|m|88

1002|liuxiaofan|m|92

1003|luzhengyu|m|96

1004|xiaohui|m|86

sqlite> select * from stu where name=fengjunhui ;

Err我爱线报网每日持续更新海量各大内部创业教程or: no such column: fengjunhui —-注意类型匹配

sqlite> select * from stu where name = fengjunhui;

1001|fengjunhui|m|88

sqlite> select * from stu where id=1003;

1003|luzhengyu|m|96

sqlite> update stu set sex = f where id=1002;

Error: no such column: f

sqlite> update stu set sex =f where id=1002;

sqlite> select * 我爱线报网每日持续更新海量各大内部创业教程from stu

…> ;

1001|fengjunhui|m|88

1002|liuxiaofan|f|92

1003|luzhengyu|m|96

1004|xiaohui|m|86

sqlite> delete from stu where name=xiaohui;

sqlite> select * from stu;

1001|fengjunhui|m|88

1002|liuxiaofan|f|92

1003|luzhengyu|m|96

sqlite> alter table stu add column age int;

sqlite> select * from stu ;

1001|fengjun我爱线报网每日持续更新海量各大内部创业教程hui|m|88|

1002|liuxiaofan|f|92|

1003|luzhengyu|m|96|

sqlite> update stu set age = 25 where id=1001;

sqlite> select * from stu;

1001|fengjunhui|m|88|25

1002|liuxiaofan|f|92|

1003|luzhengyu|m|96|

sqlite> create table stu_bak as select id,name,sex,score from stu;

sqlite> .table

stu stu_bak

sqlite> .schema

CREATE T我爱线报网每日持续更新海量各大内部创业教程ABLE stu(id int,name char,sex char,score int, age int);

CREATE TABLE stu_bak(

id INT,

name TEXT,

sex TEXT,

score INT

);

sqlite> drop table stu;

sqlite> alter table stu_bak rename to stu;

sqlite> .table

stu

sqlite> create table usr(name text primary key,passwd text);

sqlite> .talbe

Error: unknown command or inval我爱线报网每日持续更新海量各大内部创业教程id arguments: “talbe”. Enter “.help” for help

sqlite> .table

stu usr

5、sqlite3 API函数接口的使用

测试源码:

#include

#include

//注意:编译时需要手动链接库文件 -lsqlite3

#define DATABASE “student.db”

#define N 128

#define IS_NUM(index) (0 <= index && index <= 9) ? 1 : 0

int flags = 0;

int do_insert(sqlite3 *db)

{

int id;

char name[N];

int sco我爱线报网每日持续更新海量各大内部创业教程re;

char sql[N];

char *errmsg;

printf(“please input id >>> “);

scanf(“%d”, &id);

getchar();

printf(“please input name >>> “);

scanf(“%s”, name);

getchar();

printf(“please input score >>> “);

scanf(“%d”, &score);

getchar();

sprintf(sql, “insert into stu values(%d, %s, %d)”, id, name, score);

if(sqlite3_exec(db, s我爱线报网每日持续更新海量各大内部创业教程ql, NULL, NULL, &errmsg) != SQLITE_OK)

{

printf(“%s\n”, errmsg);

}

else

{

printf(“the datas is inserted successfully\n”);

}

return 0;

}

//回调函数负责得到查询的结果

int callback(void *arg, int ncolumn, char **f_value, char **f_name)

{

int i = 0;

if(flags == 0)

{

for(i = 0; i < ncolumn; i++)

{

printf(“%-11s”, f_name[i]);

}

putchar(1我爱线报网每日持续更新海量各大内部创业教程0);

flags = 1;

}

for(i = 0; i < ncolumn; i++)

{

printf(“%-11s”, f_value[i]);

}

putchar(10);

return 0;

}

//查询数据

int do_select(sqlite3 *db)

{

char *errmsg;

if(sqlite3_exec(db, “select * from stu”, callback, NULL, &errmsg) != SQLITE_OK){

printf(“%s\n”, errmsg);

}else{

printf(“the datas is selected successfully\n”);

}

ret我爱线报网每日持续更新海量各大内部创业教程urn 0;

}

int do_update(sqlite3* db)

{

int id,score;

char name[N]={0},columnname[N]={0},columntype[N]={0};

int num,index;

char* errmsg;

char sql[N]={0};

printf(“input your index for search: 1 id 2 name 3 score: \n”);

scanf(“%d”,&index);

getchar();

if(index == 1){

printf(“input id : \n”);

scanf(“%d”,&id);

}else if(i我爱线报网每日持续更新海量各大内部创业教程ndex == 2){

printf(“input name : \n”);

scanf(“%s”,name);

}else {

printf(“input score: \n”);

scanf(“%d”,&score);

}

printf(“your choice whose info to update: 1 id 2 name 3 score 4 colum: \n”);

scanf(“%d”,&num);

getchar();

switch(num)

{

case 1:

printf(“please input id: “);

scanf(“%d”,&id);

getchar();

if(index == 1){

pr我爱线报网每日持续更新海量各大内部创业教程intf(“input sorry,the same info,no need change.\n “);

}else if(index == 2){

sprintf(sql,”update stu set id=%d where name=%s”,id,name);

}else if(index == 3){

sprintf(sql,”update stu set id=%d where score=%d”,id,score);

}if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){

printf(“%s\n”,errmsg);

}

break;

c我爱线报网每日持续更新海量各大内部创业教程ase 2:

printf(“please input name: “);

scanf(“%s”,name);

getchar();

if(index == 1){

sprintf(sql,”update stu set name=%s where id=%d”,name,id);

}if(index == 2){

printf(“input sorry,the same info,no need change.\n “);

}else if(index == 3){

sprintf(sql,”update stu set name=%s where score=%d”,name,score);

}if(sqli我爱线报网每日持续更新海量各大内部创业教程te3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){

printf(“%s\n”,errmsg);

}

break;

case 3:

printf(“please input socre: “);

scanf(“%d”,&score);

getchar();

if(index == 1) {

sprintf(sql,”update stu set score=%d where id=%d”,score,id);

}else if(index == 2){

sprintf(sql,”update stu set score=%d where name=%s”,score,我爱线报网每日持续更新海量各大内部创业教程name);

} else if(index == 3){

printf(“input sorry,the same info,no need change.\n “);

}

if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){

printf(“%s\n”,errmsg);

}

break;

case 4:

printf(“please input column name: “);

scanf(“%s”,columnname);

getchar();

printf(“please input column type: INT or CHAR”);

scanf(我爱线报网每日持续更新海量各大内部创业教程“%s”,columntype);

getchar();

sprintf(sql,”alter table stu add column %s %s “,columnname,columntype);

if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){

printf(“%s\n”,errmsg);

}

break;

default:

printf(“input illegal.\n”);

}

printf(“the datas is update successfully\n”);

return 0;

}

int do_delete(sqlite3* db)我爱线报网每日持续更新海量各大内部创业教程

{

int i=0;

char table[N]={0};

int id,score,index;

char name[N]={0};

char* errmsg;

char sql[N]={0};

char *delsql[5]={0};

printf(“\n”);

do_select(db); //printf database info list

printf(“\n”);

printf(“input index for delete: 1 id 2 name 3 score 4 table 5 colum: \n”);

scanf(“%d”,&index);

getchar();

if(index == 1){

pr我爱线报网每日持续更新海量各大内部创业教程intf(“input id : \n”);

scanf(“%d”,&id);

sprintf(sql,”delete from stu where id=%d”,id);

}else if(index == 2){

printf(“input name : \n”);

scanf(“%s”,name);

sprintf(sql,”delete from stu where name=%s”,name);

}else if(index == 3){

printf(“input score: \n”);

scanf(“%d”,&score);

sprintf(sql,”delete from stu where s我爱线报网每日持续更新海量各大内部创业教程core=%d”,score);

}else if(index == 4){

printf(“input which table: \n”);

scanf(“%s”,table);

sprintf(sql,”drop table %s”,table);

}else if(index == 5){

#if 0

sprintf(delsql[0],”create table stu1 as select id,name from stu\n”);

sprintf(delsql[1],”drop table stu\n”);

sprintf(delsql[2],”alter table stu1 rename to 我爱线报网每日持续更新海量各大内部创业教程stu\n”);

#endif

delsql[0] = “create table stu1 as select id,name from stu”;

delsql[1] = “drop table stu”;

delsql[2] = “alter table stu1 rename to stu”;

for(i = 0;i < 3;i ++){

printf(“delsql[%d]: %s\n”,i,delsql[i]);

}

return 0;

}

if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){

printf(“%s\n”,errmsg);

}

re我爱线报网每日持续更新海量各大内部创业教程turn 0;

}

int main(int argc, const char *argv[])

{

sqlite3 *db;

char *errmsg;

int num;

//创建(打开)数据库

if(sqlite3_open(DATABASE, &db) != SQLITE_OK) {

printf(“%s\n”, sqlite3_errmsg(db));

}else{

printf(“the database is opened successfully\n”);

}

//创建一张表

if(sqlite3_exec(db, “create table stu(id int, name char, score int我爱线报网每日持续更新海量各大内部创业教程)”, NULL, NULL, &errmsg) != SQLITE_OK){

printf(“%s\n”, errmsg);

}else {

printf(“the table is created successfully\n”);

}

//对当前表进行增删改查

while(1)

{

printf(“\n”);

printf(“***1:插入数据 2:查询数据 3:修改数据 4:删除数据 5:退出***\n”);

printf(“\n”);

printf(“>>> “);

scanf(“%d”, &num);

getchar();

switch(num)

{

case 1:

do_insert(db);

break;

case我爱线报网每日持续更新海量各大内部创业教程 2:

flags = 0;

do_select(db);

//do_select_get_table(db);

break;

case 3:

do_update(db);

break;

case 4:

do_delete(db);

break;

case 5:

sqlite3_close(db);

return -1;

default:

printf(“please input correct option\n”);

}

}

return 0;

}

测试结果:

fengjunhui@ubuntu:~/Sqlite$ ./a.out

the database is opened successfully

table stu already我爱线报网每日持续更新海量各大内部创业教程 exists

1:插入数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 2

id name score

1001 liuxiaofan 92

1004 fengjunhui 98

1003 luzhengyu 96

the datas is selected successfully

1:插入数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 1

please input id >>> 1005

please input name >>> xiaohuihui

please input score >>> 76

the datas is inserted successfully

1:插入我爱线报网每日持续更新海量各大内部创业教程数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 3

input your index for search: 1 id 2 name 3 score:

1

input id :

1004

your choice whose info to update: 1 id 2 name 3 score 4 colum:

3

please input socre: 88

the datas is update successfully

1:插入数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 2

id name score

1001 liuxiaofan 92

1004 fengjunhui 88我爱线报网每日持续更新海量各大内部创业教程

1003 luzhengyu 96

1005 xiaohuihui 76

the datas is selected successfully

1:插入数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 4

1001 liuxiaofan 92

1004 fengjunhui 88

1003 luzhengyu 96

1005 xiaohuihui 76

the datas is selected successfully

input index for delete: 1 id 2 name 3 score 4 table 5 colum:

2

input name :

fengjunhui

no suc我爱线报网每日持续更新海量各大内部创业教程h column: fengjunhui

1:插入数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 2

id name score

1001 liuxiaofan 92

1004 fengjunhui 88

1003 luzhengyu 96

1005 xiaohuihui 76

the datas is selected successfully

1:插入数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 5

fengjunhui@ubuntu:~/Sqlite$ gcc 5_student.c -lsqlite3

fengjunhui@ubuntu:~/Sqlite$ ./a.out我爱线报网每日持续更新海量各大内部创业教程

the database is opened successfully

table stu already exists

1:插入数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 4

id name score

1001 liuxiaofan 92

1004 fengjunhui 88

1003 luzhengyu 96

1005 xiaohuihui 76

the datas is selected successfully

input index for delete: 1 id 2 name 3 score 4 table 5 colum:

2

input name :

fengjunhui

1:插我爱线报网每日持续更新海量各大内部创业教程入数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 2

id name score

1001 liuxiaofan 92

1003 luzhengyu 96

1005 xiaohuihui 76

the datas is selected successfully

1:插入数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 5

fengjunhui@ubuntu:~/Sqlite$ gcc 5_student.c -lsqlite3

fengjunhui@ubuntu:~/Sqlite$ ./a.out

the database is opened successfully

table 我爱线报网每日持续更新海量各大内部创业教程stu already exists

1:插入数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 4

id name score

1001 liuxiaofan 92

1003 luzhengyu 96

1005 xiaohuihui 76

the datas is selected successfully

input index for delete: 1 id 2 name 3 score 4 table 5 colum:

5

delsql[0]: create table stu1 as select id,name from stu

delsql[1]: drop table stu

dels我爱线报网每日持续更新海量各大内部创业教程ql[2]: alter table stu1 rename to stu

1:插入数据 2:查询数据 3:修改数据 4:删除数据 5:退出

>>> 5

扩展内容:

sqlite3支持的数据类型:

NULL、INTEGER、REAL、TEXT、BLOB

但是,sqlite3也支持如下的数据类型

smallint 16位整数

integer 32位整数

decimal(p,s) p是精确值,s是小数位数

float 32位实数

double 64位实数

char(n) n长度字符串,不能超过254

varchar(n) 长度不固定大字符串长度为n,n不超过4000

graphic(n) 和 char(n) 一样,但是单位是我爱线报网每日持续更新海量各大内部创业教程两个字符double-bytes,n不超过127(中文字)

vargraphic(n) 可变长度且大长度为n

date 包含了年份、月份、日期

time 包含了小时、分钟、秒

timestamp 包含了年、月、日、时、分、秒、千分之一秒

sqlite3支持的函数

【1】日期函数

datetime() : 产生日期和时间

date(): 产生日期

time():产生时间

strftime():对以上3个函数产生的日期和时间进行格式化

用法实例:

1、select date(2011-9-9,+1 day,+1 year); 结果是 2010-09-10

2、select datetime(now); 当前日期和时间

3、s我爱线报网每日持续更新海量各大内部创业教程elect datetime(now, start of month); 本月的第一天零点,也可以设置年和日的第一天

4、select datetime(now,+1 hour,-12 minute); 当前时间加48分钟

strftime()函数可以将YYYY-MM-DD HH:MM:SS格式的日期字符串转换为其它形式的字符串

%d:天数,01-31

%f :小数形式的秒,SS.SSS

%H:小时

%j :某一天是该年的第几天,001-366

%m:月份,00-12

%M:分钟,00-59

%s:从1970到现在的秒数

%S:秒,00-59

%w:星期,0-6,0是星期天

%W:某天是该年的第几周,01-53

%Y:我爱线报网每日持续更新海量各大内部创业教程年,YYYY

%% 百分号

应用举例:

select strftime(%Y.%m.%d %H:%M:%S,now,localtime);

二、【算术函数】

abs(X):返回绝对值

max(X,Y[,…]):返回大值

min(X,Y,[,…]):返回小值

random(*):返回随机数

round(X[,Y]): 四舍五入

三、【字符串处理函数】

length(x) :返回字符串字符个数

lower(x) :大写转小写

upper(x):小写转大写

substr(x,y,Z):截取子串

like(A,B):确定给定的字符串与指定的模式是否匹配

嵌入式物联网需要学的东西真的非常多,千万不要学错了路线和内容,导致工资要我爱线报网每日持续更新海量各大内部创业教程不上去!

无偿分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!某鱼上买估计至少要好几十。加微信领取资料

推荐阅读

给力项目线报网会员可免费下载 加入会员
友情提醒: 请尽量登录购买,防止付款了不发货!
QQ交流群:226333560 站长微信:qgzmt2
温馨提示:本站提供的一切软件、教程和内容信息都来自网络收集整理,仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负,版权争议与本站无关。用户必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。如果您喜欢该程序和内容,请支持正版,购买注册,得到更好的正版服务。我们非常重视版权问题,如有侵权请邮件与我们联系处理。敬请谅解!

给TA打赏
共{{data.count}}人
人已打赏
行业资讯

爱购团购888正规么(爱购团购)

2024-5-13 12:26:18

行业资讯

淘宝的免费推广(2019最新淘宝店铺8种免费推广方法)

2024-5-13 12:47:57

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索