嵌入式数据库sqlite3

目录

一、数据库

数据库的基本概念​编辑

 常用的数据库

基于嵌入式的数据库

二、SQLite

SQLite基础

SQLite安装

安装可视化工具

数据库命令:   

​编辑

​编辑

三、sqlite3 数据库 C语言 API 

四、基于数据库的学生管理系统

​编辑

五、一个小作业


一、数据库

数据库的基本概念

 常用的数据库

大型数据库

Oracle公司是最早开发关系数据库的厂商之一,其产品支持最广泛的操作系统平台。目前Oracle关系数据库产品的市场占有率名列前茅。

IBM 的DB2是第一个具备网上功能的多媒体关系数据库管理系统,支持包Linux在内的一系列平台。

中型数据库

Server是微软开发的数据库产品,主要支持windows平台。

小型数据库

mySQL是一个小型关系型数据库管理系统,开发者为瑞典MySQL AB公司,2008年被Sun公司收购,开放源码。现在Sun又被Oracle收购了

数据库种类大全及区别_seniorShen的博客-CSDN博客_数据库分类

我接触过的第一款就是免费开源的MySQL,在JavaWeb开发中常用

后面学习大数据接触到了第一个NoSQL它叫Hbase  ,这些非关系型数据库常用于大数据处理中。 

基于嵌入式的数据库

基于嵌入式Linux的数据库主要有SQLite, Firebird, Berkeley DB, eXtremeDB

Firebird是关系型数据库,功能强大,支持存储过程、SQL兼容等

SQLite关系型数据库,体积小,支持ACID事务

Berkeley DB中并没有数据库服务器的概念,它的程序库直接链接到应用程序中

eXtremeDB是内存数据库,运行效率

嵌入式数据库_百度百科

二、SQLite

SQLite基础

SQLite的源代码是C,其源代码完全开放。SQLite第一个Alpha版本诞生于20005月。 他是一个轻量级的嵌入式数据库

SQLite有以下特性

零配置一无需安装和管理配置;

储存在单一磁盘文件中的一个完整的数据库;

数据库文件可以在不同字节顺序的机器间自由共享;

支持数据库大小至2TB

足够小,全部源码大致3万行c代码,250KB

比目前流行的大多数数据库对数据的操作要快;

SQLite安装

准备好安装包

 

这时候dpkg的弊端就出现了,老师给的安装包太老了,相关依赖都木有,所以还是apt安装吧

先更新下软件包sudo apt update

 报错了

先执行

sudo pkill -KILL appstreamcli

在执行

wget -P /tmp https://launchpad.net/ubuntu/+archive/primary/+files/appstream_0.9.4-1ubuntu1_amd64.deb https://launchpad.net/ubuntu/+archive/primary/+files/libappstream3_0.9.4-1ubuntu1_amd64.deb 

 最后执行

sudo dpkg -i /tmp/appstream_0.9.4-1ubuntu1_amd64.deb /tmp/libappstream3_0.9.4-1ubuntu1_amd64.deb

运行完了再来更新

 

我真是yue了,算了先不管它

直接  sudo apt install sqlite3

 吐了呀

如何解决apt-get中Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify的问题_疏狂的博客-CSDN博客_unmet dependencies. try 'apt --fix-broken install'

 按照这个解决一下第一步   sudo apt --fix-broken install

 太好了没报错

 我在更新

爱了爱了

 成功好像在招手

查看版本

安装可视化工具

sudo apt-get install sqlitebrowser

sqlitebrowser 数据库名查看数据库

数据库命令:   

1)系统命令 , 都以'.'开头
         .help   帮助

         .exit      退出
         .quit    退出sql命令行
         .table   查看表
         .schema  查看表的结构

英文文档

.archive ...           Manage SQL archives: ".archive --help" for details
.auth ON|OFF           Show authorizer callbacks
.backup ?DB? FILE      Backup DB (default "main") to FILE
.bail on|off           Stop after hitting an error.  Default OFF
.binary on|off         Turn binary output on or off.  Default OFF
.cd DIRECTORY          Change the working directory to DIRECTORY
.changes on|off        Show number of rows changed by SQL
.check GLOB            Fail if output since .testcase does not match
.clone NEWDB           Clone data into NEWDB from the existing database
.databases             List names and files of attached databases
.dbinfo ?DB?           Show status information about the database
.dump ?TABLE? ...      Dump the database in an SQL text format
                         If TABLE specified, only dump tables matching
                         LIKE pattern TABLE.
.echo on|off           Turn command echo on or off
.eqp on|off|full       Enable or disable automatic EXPLAIN QUERY PLAN
.excel                 Display the output of next command in a spreadsheet
.exit                  Exit this program
.expert                EXPERIMENTAL. Suggest indexes for specified queries
.fullschema ?--indent? Show schema and the content of sqlite_stat tables
.headers on|off        Turn display of headers on or off
.help                  Show this message
.import FILE TABLE     Import data from FILE into TABLE
.imposter INDEX TABLE  Create imposter table TABLE on index INDEX
.indexes ?TABLE?       Show names of all indexes
                         If TABLE specified, only show indexes for tables
                         matching LIKE pattern TABLE.
.limit ?LIMIT? ?VAL?   Display or change the value of an SQLITE_LIMIT
.lint OPTIONS          Report potential schema issues. Options:
                         fkey-indexes     Find missing foreign key indexes
.load FILE ?ENTRY?     Load an extension library
.log FILE|off          Turn logging on or off.  FILE can be stderr/stdout
.mode MODE ?TABLE?     Set output mode where MODE is one of:
                         ascii    Columns/rows delimited by 0x1F and 0x1E
                         csv      Comma-separated values
                         column   Left-aligned columns.  (See .width)
                         html     HTML <table> code
                         insert   SQL insert statements for TABLE
                         line     One value per line
                         list     Values delimited by "|"
                         quote    Escape answers as for SQL
                         tabs     Tab-separated values
                         tcl      TCL list elements
.nullvalue STRING      Use STRING in place of NULL values
.once (-e|-x|FILE)     Output for the next SQL command only to FILE
                         or invoke system text editor (-e) or spreadsheet (-x)
                         on the output.
.open ?OPTIONS? ?FILE? Close existing database and reopen FILE
                         The --new option starts with an empty file
.output ?FILE?         Send output to FILE or stdout
.print STRING...       Print literal STRING
.prompt MAIN CONTINUE  Replace the standard prompts
.quit                  Exit this program
.read FILENAME         Execute SQL in FILENAME
.restore ?DB? FILE     Restore content of DB (default "main") from FILE
.save FILE             Write in-memory database into FILE
.scanstats on|off      Turn sqlite3_stmt_scanstatus() metrics on or off
.schema ?PATTERN?      Show the CREATE statements matching PATTERN
                          Add --indent for pretty-printing
.selftest ?--init?     Run tests defined in the SELFTEST table
.separator COL ?ROW?   Change the column separator and optionally the row
                         separator for both the output mode and .import
.session CMD ...       Create or control sessions
.sha3sum ?OPTIONS...?  Compute a SHA3 hash of database content
.shell CMD ARGS...     Run CMD ARGS... in a system shell
.show                  Show the current values for various settings
.stats ?on|off?        Show stats or turn stats on or off
.system CMD ARGS...    Run CMD ARGS... in a system shell
.tables ?TABLE?        List names of tables
                         If TABLE specified, only list tables matching
                         LIKE pattern TABLE.
.testcase NAME         Begin redirecting output to 'testcase-out.txt'
.timeout MS            Try opening locked tables for MS milliseconds
.timer on|off          Turn SQL timer on or off
.trace FILE|off        Output each SQL statement as it is run
.vfsinfo ?AUX?         Information about the top-level VFS
.vfslist               List all available VFSes
.vfsname ?AUX?         Print the name of the VFS stack
.width NUM1 NUM2 ...   Set column widths for "column" mode
                         Negative values right-justify
 

 2)sql语句, 都以‘;’结尾

        1-- 创建一张表
            create table stuinfo(id integer, name text, age integer, score float);
        
        2-- 插入一条记录
            insert into stuinfo values(1001, 'zhangsan', 18, 80);
            insert into stuinfo (id, name, score) values(1002, 'lisi', 90);

        3-- 查看数据库记录
            select * from stuinfo;
            select * from stuinfo where score = 80;
            select * from stuinfo where score = 80 and name= 'zhangsan';
            select * from stuinfo where score = 80 or name='wangwu';
            select name,score from stuinfo;  查询指定的字段
            select * from stuinfo where score >= 85 and score < 90;

        4-- 删除一条记录
            delete from stuinfo where id=1003 and name='zhangsan';

插入的时候把wangyu插到得分里了,不对怎么删王五了重来

 

 

SQLite不会检查数据类型

        5-- 更新一条记录
            update stuinfo set age=20 where id=1003;
            update stuinfo set age=30, score = 82 where id=1003;

        6-- 删除一张表
            drop table stuinfo;

        7-- 增加一列
            alter table stuinfo add column sex char;

 

        8-- 删除一列(不支持直接删除,创建新表删除旧表将新表名改成旧表)
            create table stu as select id, name, score from stuinfo;
            drop table stuinfo;
            alter table stu rename to stuinfo;

     9、数据库设置主键和自增:
     create table info(id integer primary key autoincrement, name vchar);

三、sqlite3 数据库 C语言 API 

 int sqlite3_open(
      const char *filename,   /* Database filename (UTF-8) */
      sqlite3 **ppDb          /* OUT: SQLite db handle */
     );
    功能:打开数据库
    参数:filename  数据库名称
          ppdb      数据库句柄
    返回值:成功为0 SQLITE_OK ,出错 错误码

    int sqlite3_close(sqlite3* db);
    功能:关闭数据库
    参数
    返回值:成功为0 SQLITE_OK ,出错 错误码

   const char *sqlite3_errmsg(sqlite3*db);
    功能:得到错误信息的描述
 
   int sqlite3_exec(
   sqlite3* db,                                  /* An open database */
  const char *sql,                           /* SQL to be evaluated */
  int (*callback)(void* arg,int,char**,char**),  /* Callback function */
  void * arg,                                    /* 1st argument to callback */
  char **errmsg                              /* Error msg written here */
  );
  功能:执行一条sql语句
  参数

        db  数据库句柄
        sql sql语句
        callback  回调函数,只有在查询时,才传参
        arg      为回调函数传递参数
        errmsg  错误消息
  返回值:成功 SQLITE_OK

查询回调函数:
int (*callback)(void* arg,int ncolumns ,char** f_value,char** f_name),  /* Callback function */
功能:查询语句执行之后,会回调此函数
参数:arg   接收sqlite3_exec 传递来的参数
      ncolumns 列数
      f_value 列的值得地址
      f_name   列的名称
返回值:0,
           
  
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 */
);
void sqlite3_free_table(char **result);

查询

四、基于数据库的学生管理系统

编译一下结果不认识sqlite3库

GCC编译错误:/ usr / bin / ld:找不到-lsqlite3.lib(GCC Compile Error: /usr/bin/ld: cannot find -lsqlite3.lib)_电脑培训

看了一下外国友人的解释我应该安一个这个

sudo apt-get install libsqlite3-dev

 

又出问题了主机和虚拟机间复制黏贴失效了

ubantu 与 主机 之间无法复制粘贴_51CTO博客_ubuntu与windows之间不能复制粘贴

sudo apt-get install open-vm-tools-desktop

好了,把代码粘过来

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>

#define  DATABASE  "student.db"
#define  N  128

int do_insert(sqlite3 *db)
{
	int id;
	char name[32] = {};
	char sex;
	int score;
	char sql[N] = {};
	char *errmsg;

	printf("Input id:");
	scanf("%d", &id);

	printf("Input name:");
	scanf("%s", name);
	getchar();

	printf("Input sex:");
	scanf("%c", &sex);

	printf("Input score:");
	scanf("%d", &score);

	sprintf(sql, "insert into stu values(%d, '%s', '%c', %d)", id, name, sex, score);

	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("Insert done.\n");
	}

	return 0;
}
int do_delete(sqlite3 *db)
{
	int id;
	char sql[N] = {};
	char *errmsg;

	printf("Input id:");
	scanf("%d", &id);

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

	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("Delete done.\n");
	}

	return 0;
}
int do_update(sqlite3 *db)
{
	int id;
	char sql[N] = {};
	char name[32] = "zhangsan";
	char *errmsg;

	printf("Input id:");
	scanf("%d", &id);

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

	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("update done.\n");
	}

	return 0;
}


int callback(void *arg, int f_num, char ** f_value, char ** f_name)
{
	int i = 0;

	for(i = 0; i < f_num; i++)
	{
	//	printf("%-8s %s", f_value[i], f_name[i]);
		printf("%-8s", f_value[i]);
	}

	printf("++++++++++++++++++++++");
	putchar(10);

	return 0;
}

int do_query(sqlite3 *db)
{
	char *errmsg;
	char sql[N] = "select count(*) from stu where name='zhangsan';";

	if(sqlite3_exec(db, sql, callback,NULL , &errmsg) != SQLITE_OK)
	{
		printf("%s", errmsg);
	}
	else
	{
		printf("select done.\n");
	}
}

int do_query1(sqlite3 *db)
{
	char *errmsg;
	char ** resultp;
	int nrow;
	int ncolumn;

	if(sqlite3_get_table(db, "select * from stu", &resultp, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
		return -1;
	}
	else
	{
		printf("query done.\n");
	}

	int i = 0;
	int j = 0;
	int index = ncolumn;

	for(j = 0; j < ncolumn; j++)
	{
		printf("%-10s ", resultp[j]);
	}
	putchar(10);

	for(i = 0; i < nrow; i++)
	{
		for(j = 0; j < ncolumn; j++)
		{
			printf("%-10s ", resultp[index++]);
		}
		putchar(10);
	}

return 0;
}

int main(int argc, const char *argv[])
{
	sqlite3 *db;
	char *errmsg;//errmsg是一个二级指针,定义一个一级指针取地址。
	int n;
	
	if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
	{
		printf("%s\n", sqlite3_errmsg(db));
		return -1;
	}
	else
	{
		printf("open DATABASE success.\n");
	}

	if(sqlite3_exec(db, "create table if not exists stu(id int, name char , sex char , score int);",NULL, NULL, &errmsg) != SQLITE_OK)//分号可加可不加
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("Create or open table success.\n");
	}

	while(1)
	{
		printf("********************************************\n");
		printf("1: insert  2:query  3:delete 4:update 5:quit\n");
		printf("********************************************\n");
		printf("Please select:");
		scanf("%d", &n);

		switch(n)
		{
			case 1:
				do_insert(db);
				break;
			case 2:
				do_query(db);
			//	do_query1(db);
				break;
			case 3:
				do_delete(db);
				break;
			case 4:
				do_update(db);
				break;
			case 5:
				printf("main exit.\n");
				sqlite3_close(db);
				exit(0);
				break;
			default :
				printf("Invalid data n.\n");
		}

	}



	return 0;
}
















五、一个小作业

写了好久,代码不是很完善但是基本功能都实现了,并预留了接口等什么时候不忙了进行二次开发。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#include <time.h>

#define  DATABASE  "fruit.db"
#define  N  128

int do_insert(sqlite3 *db)
{
	int id;
	char name[32] = {};
	float price;
	int number;
	char sql[N] = {};
	char *errmsg;

	printf("Input id:");
	scanf("%d", &id);
	puts("");
	printf("Input name:");
	scanf("%s", name);
	getchar();
	puts("");
	printf("Input price:");
	scanf("%f", &price);
	puts("");
	printf("Input number:");
	scanf("%d", &number);
	puts("");
	sprintf(sql, "insert into fruit values(%d, '%s', %f, %d)", id, name, price, number);

	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("stock done.\n");
	}

	return 0;
}
int do_delete(sqlite3 *db)
{
	int id;
	char sql[N] = {};
	char *errmsg;
	char a;
	char name[32] = {};
	printf("Are you sure you don`t want this fruit!(Y/N)\n");
	scanf("%c",&a);
	if (a == 'Y' || a == 'y'){
		printf("Input fruit:");
		scanf("%s", name);
		getchar();
		puts("");
		sprintf(sql, "delete from fruit where name = '%s'", name);

		if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
		{
			printf("%s\n", errmsg);
		}
		else
		{
			printf("Delete done.\n");
		}
	}
	return 0;
}
int do_update(sqlite3 *db)
{
	int id;
	char sql[N] = {};
	char name[32] = {};
	char *errmsg;
	float price;

	printf("Input fruit:");
	scanf("%s", name);
	getchar();
	puts("");
	printf("Input price");
	scanf("%f", &price);
	puts("");
	sprintf(sql, "update fruit set price=%f where name = '%s'", price,name);

	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("update done.\n");
	}

	return 0;
}


int callback(void *arg, int f_num, char ** f_value, char ** f_name)
{
	int i = 0;

	for(i = 0; i < f_num; i++)
	{
	//	printf("%-8s %s", f_value[i], f_name[i]);
		printf("%-8s", f_value[i]);
	}

	printf("\n++++++++++++++++++++++++++++++++");
	putchar(10);

	return 0;
}

int do_query(sqlite3 *db)
{
	printf("++++++++++++++++++++++++++++++++\n");
	char *errmsg;
	//char sql[N] = "select count(*) from fruit where name='zhangsan';";
	char sql[N] = "select * from fruit;";
	if(sqlite3_exec(db, sql, callback,NULL , &errmsg) != SQLITE_OK)
	{
		printf("%s", errmsg);
	}
	else
	{
		printf("select done.\n");
	}
}

int do_query1(sqlite3 *db)
{
	char *errmsg;
	char ** resultp;
	int nrow;
	int ncolumn;

	if(sqlite3_get_table(db, "select * from fruit", &resultp, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
		return -1;
	}
	else
	{
		printf("query done.\n");
	}

	int i = 0;
	int j = 0;
	int index = ncolumn;

	for(j = 0; j < ncolumn; j++)
	{
		printf("%-10s ", resultp[j]);
	}
	putchar(10);

	for(i = 0; i < nrow; i++)
	{
		for(j = 0; j < ncolumn; j++)
		{
			printf("%-10s ", resultp[index++]);
		}
		putchar(10);
	}

return 0;
}
#if 0  //FIXME//cuowu
static int callback1(void *data,int argc,char **argv,char **azColName)
{
	int i;
	fprintf(stderr,"%s:",(const char *)data);
	for(i=0;i<argc;i++)
	{
		printf("%s = %s\n",azColName[i],argv[i] ? argv[i]:"NULL");
	}
	printf("\n");
	return 0;
}
//查询主函数
int select_db(sqlite3 *db,char *tbname)
{
	Stu s1 = {};
	char sql[100] = {'\0'};
	sprintf(sql,"select * from %s",tbname);
	printf("%s\n",sql);
	
	char *errmsg = NULL;
	if(sqlite3_exec(db,sql,callback,NULL,&errmsg)!=SQLITE_OK)
	{
		printf("%s\n",errmsg);
		return -1;
	}
	printf("select ok\n");
	return 0;
}
#endif

int do_sell(sqlite3 *db)
{
	int id;
	char sql[N] = {};
	char sql2[N] = {};
	char name[32] = {};
	char *errmsg;
	float price;
	int number;
	time_t times;
	struct tm* ge;
	times = time(NULL);
	char buf[32];
	sprintf(buf,"%4d-%2d-%2d %2d:%2d:%2d",ge->tm_year+1900,ge->tm_mon+1,ge->tm_mday,ge->tm_hour,ge->tm_min,ge->tm_sec);	

	printf("Input fruit:");
	scanf("%s", name);
	getchar();
	puts("");
	printf("Input number");
	scanf("%d", &number);
	puts("");

	sprintf(sql2, "insert into sell values(%d, '%s', %f, %d, '%s')", id, name, price, number, buf);
	if(sqlite3_exec(db, sql2, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("stock done.\n");
	}

#if 1
	char *errmsg1;
	char ** resultp;
	int nrow;
	int ncolumn;
	char sql1[N] = {};

	sprintf(sql,"select number from fruit where name = '%s';",name);	

	if(sqlite3_get_table(db, sql1, &resultp, &nrow, &ncolumn, &errmsg1) != SQLITE_OK)
	{
		printf("%s\n", errmsg1);
		return -1;
	}
	else
	{
		number = (int)resultp - number;
		printf("query done.\n");
	}
#endif

	
	sprintf(sql, "update fruit set number='%d' where name='%s'", number, name);

	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("sell done.\n");
	}

	return 0;
}
void help()
{
	printf("1:stock,Input id,name,price,number\n");
	printf("2:Inquire the price and allowance of all fruits\n");
	printf("3:Delete fruit that is sold out and never comes in again\n");
	//XXX
}
int do_stock_list(db)
{
	//TODO
	return 0;
}
int do_sell_list(db)
{
	//TODO
	return 0;
}
int main(int argc, const char *argv[])
{
	sqlite3 *db;
	char *errmsg;//errmsg是一个二级指针,定义一个一级指针取地址。
	int n;
	
	if(sqlite3_open(DATABASE, &db) != SQLITE_OK)//打开数据库
	{
		printf("%s\n", sqlite3_errmsg(db));
		return -1;
	}
	else
	{
		printf("open DATABASE success.\n");
	}

	if(sqlite3_exec(db, "create table if not exists fruit(id int, name char , price float , number int);",NULL, NULL, &errmsg) != SQLITE_OK)//分号可加可不加  商品价格数量表
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("Create or open table success.\n");
	}

	if(sqlite3_exec(db, "create table if not exists sell(id int, name char , price float ,number int, time char);",NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("Create or open table success.\n");
	}

	while(1)
	{
		printf("*******************************************************************************\n");
		printf("1:stock 2:price 3:delete 4:update 5:quit 6:sell 7:stock_list 8:sell_list 9:help\n");
		printf("*******************************************************************************\n");
		printf("Please select:");
		scanf("%d", &n);

		switch(n)
		{
			case 1:
				do_insert(db);
				break;
			case 2:
				do_query(db);
			//	do_query1(db);
				break;
			case 3:
				do_delete(db);
				break;
			case 4:
				do_update(db);
				break;
			case 5:
				printf("main exit.\n");
				sqlite3_close(db);
				exit(0);
				break;
			case 6:
				do_sell(db);
				break;
//XXX//mianqiangnenggongzuo
			case 7:
				do_stock_list(db);
				break;
			case 8:
				do_sell_list(db);
				break;
			case 9:
				help();
				break;
			default :
				printf("Input error\n");
		}

	}

	return 0;
}











 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇努力学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值