SQLite数据库C_C++接口(保姆级API应用 1.4W字)(全网最详细介绍,学完必掌握)
目录
sqlite3的C/C++ API应用
前言
SQLite3库安装
API函数
打开、关闭、错误处理
打开
返回值
关闭
错误调试
实际应用
执行SQL(DDL、DML)
API介绍
实际应用
回调函数查询
API介绍
实际应用
全缓冲查询
API介绍
实际应用
字节缓冲查询
API介绍
实际应用
三种查询方式总结
sqlite实现C语言自定义函数封装
sqlite3的C/C++ API应用
前言
对于主键和外键知识点的补充:
- 主键的值不能重复,一般将自增的字段设置为主键。
- 主键是用来唯一表示一条数据的值,不能重复的。比如,一条记录包括身份正号,姓名,年龄。身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证号薯磨是主键。
- 外键主要目的是控制存储在外键表中的数据。 使两张表形成关联,外键只能引用外表中的列的值或使用空值。
- 外键用于与另一张表的关联。是能确定另一张表记录的字段,用于保持数据的一致性。比如,A表中的一个字段,是B表的主键,那他就可以是A表的外键。
SQLite3库安装
在 C/C++ 程序中使用 SQLite 之前,我们需要确保机器上已经有 SQLite 库,这个库提供了C/C++的操作SQLite的编程接口API。
- 在linux下只需输入安装命令:sudo apt-get install libsqlite3-dev
- QT下使用SQLite3数据库
https://www.cnblogs.com/tfanalysis/p/4073756.html
- Windows下:https://www.cnblogs.com/White-strategy-group/p/6360003.html
我使用的是Windows下通过vscode远程SSH访问Linux,因此需要在windows下也安装并添加相应的库文件。
安装前,我们在vscode中添加SQLite的头文件,提示找不到头文件
因此我们需要先定位头文件包含路径
然后到sqlite官网下载源码包(sqlite3的源码)
https://www.cnblogs.com/White-strategy-group/p/6360003.html
解压缩后文件内容如图所示
将三个.h文件添加到之前的includePath中:"D:/myinclude/**"
我们先在目录下新建一个sqlite文件夹
然后将头文件添加进来
如果发现添加完之后仍然自动找不到头文件,如下所示
我们需要手动包含具体头文件路径,如:"D:\\myinclude\\sqlite3"
我们输入sqlite3发现,可以自动提示补全,则表示库文件添加成功!
API函数
打开、关闭、错误处理
打开
第一个参数为指定要打开的数据库的名字,也包括数据库的路径
第二个参数为一个二级指针,这里的作用相当于文件描述符,它是一个数据库文件指针。传入的是一个一级指针的地址作为输出,给指针的具体指向赋值(定义一个空指针传入过来,最终会给这个指针赋值)(通过操作数据库文件指针就相对于操作数据库)
返回值
SQLite3的C/C++接口函数所有返回值如下:
#define SQLITE_OK 0 /* Successful result */
#define SQLITE_ERROR 1 /* SQL error or missing database */
#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
#define SQLITE_BUSY 5 /* The database file is locked */
#define SQLITE_LOCKED 6 /* A table in the database is locked */
#define SQLITE_NOMEM 7 /* A malloc() failed */
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */
#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */
#define SQLITE_MISMATCH 20 /* Data type mismatch */
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* Authorization denied */
#define SQLITE_ROW 100 /* sqlite_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite_step() has finished executing */
关闭
错误调试
返回错误信息
返回值错误码
实际应用
#include <stdio.h>
#include <sqlite3.h>int main(int argc, char const *argv[])
{sqlite3 *db;int ret = sqlite3_open(argv[1],&db);if(ret != SQLITE_OK){printf("sqlite3 open:%s\n",sqlite3_errmsg(db));exit(-1);}printf("sqlite open db successfully!\n");sqlite3_close(db);return 0;
}
编译的时候,不能直接编译
我们需要像使用POSIX库一样,手动链接sqlite3库
运行结果:
但是该函数有个bug,即使不传任何参数,也不会报错
因此最好添加一个命令行传参判断
#include <stdio.h>
#include <sqlite3.h>int main(int argc, char const *argv[])
{if(argc != 2){printf("Please input db name!\n");exit(-1);}sqlite3 *db;int ret = sqlite3_open(argv[1],&db);if(ret != SQLITE_OK){printf("sqlite3 open:%s\n",sqlite3_errmsg(db));exit(-1);}printf("sqlite open db successfully!\n");sqlite3_close(db);return 0;
}
执行SQL(DDL、DML)
API介绍
执行SQL语句函数,该函数一共有5个参数
参数1:数据库文件句柄
参数2:要执行的SQL语句
参数3:回调函数,传入一个函数指针(这里的sqlite_callback callback中的sqlite_callback是通过函数指针重命名的,如下图所示)。注:回调函数只对SQL查询语句有效。当指定的是一个非查询操作,该参数应该置为NULL,否则即使传入了回调函数,回调函数也不会被执行。
参数4:回调函数的参数
参数5:保存执行SQL后的错误信息,传入的是一级指针的地址
实际应用
我们首先创建一个学生表,其中我们对错误检查进行了二次封装
#include <stdio.h>
#include <sqlite3.h>
#include <string.h>
#include <stdlib.h>void print_error(int ret, char *err, sqlite3 *db)
{if(ret != SQLITE_OK){printf("%s:%s\n",err,sqlite3_errmsg(db));exit(-1);}
}int main(int argc, char const *argv[])
{if(argc != 2){printf("Please input db name!\n");exit(-1);}sqlite3 *db;char *errmsg;char sql[1024] = {0};int ret = sqlite3_open(argv[1],&db);print_error(ret,"sqlite open",db);printf("sqlite open db successfully!\n");strcpy(sql,"create table student(id integer primary key, name text, age integer)");ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);print_error(ret,"sqlite exec create table",db);printf("create table successfully\n");sqlite3_close(db);return 0;
}
然后通过键盘输入的方式往表里插入三条数据
#include <stdio.h>
#include <sqlite3.h>
#include <string.h>
#include <stdlib.h>void print_error(int ret, char *err, sqlite3 *db)
{if(ret != SQLITE_OK){printf("%s:%s\n",err,sqlite3_errmsg(db));exit(-1);}
}int main(int argc, char const *argv[])
{if(argc != 2){printf("Please input db name!\n");exit(-1);}sqlite3 *db;char *errmsg;char sql[1024] = {0};int id;char name[20];int age;int ret = sqlite3_open(argv[1],&db);print_error(ret,"sqlite open",db);printf("sqlite open db successfully!\n");strcpy(sql,"create table if not exists student(id integer primary key, name text, age integer)");ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);print_error(ret,"sqlite exec create table",db);printf("create table successfully\n");//插入3行数据:id,name,age 键盘输入for(int i=0;i<3;i++){printf("Please input id:\n");scanf("%d",&id);printf("Please input name:\n");scanf("%s",name);printf("Please input age:\n");scanf("%d",&age);//sql:insert into student(id,name,age)values();//sprint();写入到字符串 fprintf();写入到文件memset(sql,0,sizeof(sql));sprintf(sql,"insert into student(id,name,age)values(%d,'%s',%d)",id,name,age);ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);print_error(ret,"sqlite exec create table",db);}sqlite3_close(db);return 0;
}
如果我们想要删除zhangsan的数据,可以使用如下
#include <stdio.h>
#include <sqlite3.h>
#include <string.h>
#include <stdlib.h>
#define DELETE_DATA 1
#define INSERT_DATA 0
void print_error(int ret, char *err, sqlite3 *db)
{if(ret != SQLITE_OK){printf("%s:%s\n",err,sqlite3_errmsg(db));exit(-1);}
}int main(int argc, char const *argv[])
{if(argc != 2){printf("Please input db name!\n");exit(-1);}sqlite3 *db;char *errmsg;char sql[1024] = {0};int id;char name[20];int age;int ret = sqlite3_open(argv[1],&db);print_error(ret,"sqlite open",db);printf("sqlite open db successfully!\n");strcpy(sql,"create table if not exists student(id integer primary key, name text, age integer)");ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);print_error(ret,"sqlite exec create table",db);printf("create table successfully\n");#if INSERT_DATA//插入3行数据:id,name,age 键盘输入for(int i=0;i<3;i++){printf("Please input id:\n");scanf("%d",&id);printf("Please input name:\n");scanf("%s",name);printf("Please input age:\n");scanf("%d",&age);//sql:insert into student(id,name,age)values();//sprint();写入到字符串 fprintf();写入到文件memset(sql,0,sizeof(sql));sprintf(sql,"insert into student(id,name,age)values(%d,'%s',%d)",id,name,age);ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);print_error(ret,"sqlite exec create table",db);}
#endif#if DELETE_DATAprintf("Please input who do you want to delete:\n");memset(sql,0,sizeof(sql));memset(name,0,sizeof(name));scanf("%s",name);sprintf(sql,"delete from student where name = '%s'",name);ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);print_error(ret,"sqlite exec delete data",db);
#endifsqlite3_close(db);return 0;
}
注:SQLite库提供的是原生态的接口,我们可以对其进行二次封装,像之前错误检查那样,对sqlite3_exec要执行的SQL语句,进行封装,避免代码的冗余。
回调函数查询
API介绍
每查询到一条结果就会回调一次这个函数,通过一行行缓冲数据,每次缓冲一行。
参数1:传入的参数
参数2:保存查询到的结果每一行中列的个数
参数3:保存查询到数据中每一列的值,用一个指针数组(保存指针的数组,本质是数组)来接
参数4:保存每一列的字段名字,用一个指针数组来接
实际应用
以打印查询到的结果每行列数为例:如果回调函数不加return 0;,那么将只执行一次
将上return 0;,才可以执行全部
如果想要打印查询到的每一列结果
再加上每一列相应的字段名
注意:对于外部传入回调函数的参数是无法修改的(具体原因可能是由于内部机制)
如:我们传入一个flag变量,然后出函数打印结果
我们在回调函数内对flag进行++
但出函数之后,值仍是0
如果查询不到结果,将会什么信息也不会输出
我们可以通过定义一个全局变量标志位进行判断,是否查询到数据
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <string.h>int flag=0;void print_error(int ret, char *err, sqlite3 *db)
{if(ret != SQLITE_OK){printf("%s:%s\n",err,sqlite3_errmsg(db));exit(-1);}printf("%s:successfully!\n",err);
}int my_sqlite_callback(void *para,int columnCount,char **columnValue,char**columnName)
{printf("columnCount = %d\n", columnCount);flag=1;for(int i = 0; i < columnCount;i++){printf("%s:%s|",columnName[i],columnValue[i]);}printf("\n");return 0;
}int main(int argc, char const *argv[])
{if(argc != 2){printf("Please input db name!\n");exit(-1);}sqlite3 *db;char *errmsg;char sql[1024] = {0};int ret = sqlite3_open(argv[1],&db);print_error(ret,"sqlite open",db);printf("sqlite open db successfully!\n");strcpy(sql,"select * from student where name = 'zhangsan'");sqlite3_exec(db,sql,my_sqlite_callback,NULL,&errmsg);print_error(ret,"select",db);if(flag==0){printf("The data queried is empty!\n");}sqlite3_close(db);return 0;
}
全缓冲查询
API介绍
与sqlite_exec不同,sqlite3_get_table是专门用于查询数据的,通过一次性将所有查询到的数据缓冲起来
参数1:数据库文件句柄
参数2:数据库SQL语句
参数3:三维指针,用于保存查询到的结果
参数4:查询到的结果总共的行数
参数5:查询到的结果总共的列数
参数6:保存查询出错的信息
以三维指针为例,我们可以创建一个变相的二维数组:
可以想象创建一个长方体
char ***result;
result = (char***)malloc(sizeof(char**)*4);创建四个存储空间
*result = (char**)malloc(sizeof(char*)*4);每个存储空间里再创建四个存储空间
**result = (char*)malloc(sizeof(char)*4);每个存储空间里再创建一个字符串数组
最终在逻辑上形成16个连续的存储空间(物理上不连续)
我们可以通过三次for循环来创建
但访问方式仍是一维数组的访问方式,因为通过指针创建的空间,本质还是链式的,不是真正的多维数组
实际应用
实际使用时,我们需要定义一个二维指针,将它的地址作为参数传入,查询到的数据都将保存在二维指针中
发现打印是从字段开始打印的,最后少了一行数据,这是因为保存的数据包括了字段那一行,但是返回的行数nrow只算了实际数据的行数
因此需要改正如下:
这样输出的结果就是正确的了
最后一定要记得调用释放空间函数sqlite3_free_table,因为库函数sqlite3_get_table的内部分配了堆区空间
全缓冲查询程序如下:
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <string.h>void print_error(int ret, char *err, sqlite3 *db)
{if(ret != SQLITE_OK){printf("%s:%s\n",err,sqlite3_errmsg(db));exit(-1);}printf("%s:successfully!\n",err);
}int main(int argc, char const *argv[])
{if(argc != 2){printf("Please input db name!\n");exit(-1);}sqlite3 *db;char *errmsg;char sql[1024] = {0};int ret = sqlite3_open(argv[1],&db);print_error(ret,"sqlite open",db);printf("sqlite open db successfully!\n");char **result;int nrow;int ncolumn;strcpy(sql,"select * from student");ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg);print_error(ret,"select",db);for(int i = 1; i<=nrow; i++){for(int j = 0; j < ncolumn; j++){printf("%s|",result[i*ncolumn+j]);}printf("\n");}sqlite3_free_table(result);sqlite3_close(db);return 0;
}
字节缓冲查询
API介绍
sqlite3_prepare
作用:把SQL语句转成字节码,由后面的执行函数去执行,将查询到的数据做字节缓冲
参数1:数据库文件句柄
参数2:SQL语句
参数3:SQL语句的最大字节数,一般设为-1
参数4:Statement句柄,即字节序句柄
参数5:SQL语句无用部分的指针,一般设为NULL
字节缓冲查询还涉及到了以下函数:
- sqlite3_step:从第一行开始查询,每次查询一行,每调用一次该函数会继续查询下一行数据,数据不为空则返回SQLITE_ROW
- sqlite3_column_count:获取结果的列数
- sqlite3_column_text:获取程序的结果当前行中每一列的数据
- sqlite3_finalize:用于销毁字节序句柄
实际应用
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <string.h>void print_error(int ret, char *err, sqlite3 *db)
{if(ret != SQLITE_OK){printf("%s:%s\n",err,sqlite3_errmsg(db));exit(-1);}printf("%s:successfully!\n",err);
}int main(int argc, char const *argv[])
{if(argc != 2){printf("Please input db name!\n");exit(-1);}sqlite3 *db;char *errmsg;char sql[1024] = {0};int ret = sqlite3_open(argv[1],&db);print_error(ret,"sqlite open",db);printf("sqlite open db successfully!\n");int rc,i,j;int ncolumn;sqlite3_stmt *stmt;strcpy(sql,"select * from student");rc = sqlite3_prepare(db,sql,-1,&stmt,NULL);if(rc){printf("query fail!\n");}else{printf("query success!\n");rc = sqlite3_step(stmt);//查询成功,则返回值rc==SQLITE_ROWncolumn = sqlite3_column_count(stmt);//获取列数while(rc == SQLITE_ROW){for(i = 0;i<ncolumn;i++){printf("%s|",sqlite3_column_text(stmt,i));//获取每一列的数据}printf("\n");rc = sqlite3_step(stmt);//继续获取下一行数据}}sqlite3_finalize(stmt);sqlite3_close(db);return 0;
}
三种查询方式总结
回调函数查询内存开销小,但查询效率相对较低;全缓冲查询的查询效率高,但是内存消耗大;字节缓冲查询兼具查询效率和低开销。(优先使用第三种查询方法)
sqlite实现C语言自定义函数封装
由于数据库提供的API接口过于复杂,使用的过程顺序也很繁琐,所以对于原生态的API在实际工作开发中,会进行一层封装,减少调用传参,减少调用次数,增加代码可读性,提高开发效率。
可封装如下:包括创建数据库、建表、插入数据、查询数据、删除数据
database.h
#ifndef _DATABASE_H_
#define _DATABASE_H_#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <libgen.h>
#include <sqlite3.h>extern int open_database(sqlite3 **db,char *database_name);
extern int create_table(sqlite3 **db,char *table_name,char *table_attribute);
extern int insert_data(sqlite3 **db,char *table_name,char *attr,char *msg);
extern int query_data(sqlite3 **db,char ***azResult,char *table_name);
extern int delete_data(sqlite3 **db,char *table_name);#endif
database.c
#include "database.h"char sql[128];
char *zErrMsg=NULL;
int nrow=0;
int ncolumn = 0;int open_database(sqlite3 **db,char *database_name)
{int len;len = sqlite3_open(database_name,db);if(len){printf("Open database name %s failure.\n",database_name);sqlite3_close(*db);return -1;}printf("Open a sqlite3 database name %s successfully!\n",database_name);return 0;
}int create_table(sqlite3 **db,char *table_name,char *table_attribute)
{snprintf(sql,sizeof(sql),"CREATE TABLE %s(%s);",table_name,table_attribute);//log_info("sql=%s\n",sql);//sql="CREATE TABLE test(TEST CHAR(100));";if(sqlite3_exec(*db,sql,NULL,NULL,&zErrMsg)!=SQLITE_OK){printf("Table %s already exist\n",table_name);}else{printf("Create table %s successfully\n",table_name);}}int insert_data(sqlite3 **db,char *table_name,char *attr,char *msg)
{snprintf(sql,sizeof(sql),"INSERT INTO %s(%s) VALUES('%s');",table_name,attr,msg); //插入数据if(sqlite3_exec(*db,sql,NULL,NULL,&zErrMsg)!=SQLITE_OK){sqlite3_close(*db);printf("Insert %s to table %s failure:%s\n",msg,table_name,strerror(errno));return -1;}printf("Insert %s to table %s successfully\n",msg,table_name);return 0;
}int query_data(sqlite3 **db,char ***azResult,char *table_name)
{snprintf(sql,sizeof(sql),"select *from %s;",table_name);//sql="select *from test";if(sqlite3_get_table(*db,sql,azResult,&nrow,&ncolumn,&zErrMsg)!=SQLITE_OK){sqlite3_close(*db);printf("Select *from %s failure\n",table_name);return -1;}printf("There are %d pieces of data in table %s\n",nrow,table_name);return nrow;
}int delete_data(sqlite3 **db,char *table_name)
{snprintf(sql,sizeof(sql),"delete from %s;",table_name);//sql="delete from test";if(sqlite3_exec(*db,sql,NULL,NULL,&zErrMsg)!=SQLITE_OK){sqlite3_close(*db);printf("Delete from %s failure\n",table_name);return -1;}printf("Delete data from table %s successfully!\n",table_name);return 0;
}
test_database.c
#include "database.h"int main(void)
{sqlite3 *db;char **azResult=NULL;if( open_database(&db,"test.db")<0 )return -1;if( create_table(&db,"test","TEST CHAR(100)")<0 )return -2;if( insert_data(&db,"test","TEST","Test nihao")<0 )return -3;if( query_data(&db,&azResult,"test")<0 )return -4;if( delete_data(&db,"test")<0 )return -5;if( query_data(&db,&azResult,"test")<0 )return -6;return 0;
}
相关文章:

SQLite数据库C_C++接口(保姆级API应用 1.4W字)(全网最详细介绍,学完必掌握)
目录 sqlite3的C/C API应用 前言 SQLite3库安装 API函数 打开、关闭、错误处理 打开 返回值 关闭 错误调试 实际应用 执行SQL(DDL、DML) API介绍 实际应用 回调函数查询 API介绍 实际应用 全缓冲查询 API介绍 实际应用 字节缓冲查询…...
倒计时:心理的镇静剂还是焦虑的火种?
倒计时:心理的镇静剂还是焦虑的火种? 目录 引言倒计时的作用与原理倒计时的双面性:缓解焦虑还是引发焦虑?如何正确使用倒计时结论 引言 在我们的日常生活和工作中,倒计时被广泛的应用。无论是在网购的抢购活动中&a…...
迅睿系统二开自定义函数和插件的自定义函数
全局的自定义函数: 全局的自定义函数文件:dayrui/My/Helper.php 此文件用于放网站自定义函数,程序会自动加载 当前站点的自定义函数文件:网站主目录/config/custom.php 插件的自定义函数: 基于App目录下的插件或模块…...

传统品牌如何通过3D虚拟数字人定制和动捕设备加速年轻化发展?
步入Z时代,年轻一代消费者的生活方式深受互联网技术和媒介环境影响,对新潮事物感兴趣,消费思维也相对前卫,品牌需要探索契合Z世代的消费观念,寻找新的链接拉近品牌与消费者的距离,而3D虚拟数字人定制可以帮…...

sql:SQL优化知识点记录(五)
(1)explain之例子 (2)索引单表优化案例 上面的功能已经实现,但是分析功能, 使用explain分析这条sql: 发现type为All Extra:有Using filesort (文件内排序) 这…...

1.3 Metasploit 生成SSL加密载荷
在本节中,我们将介绍如何通过使用Metasploit生成加密载荷,以隐藏网络特征。前一章节我们已经通过Metasploit生成了一段明文的ShellCode,但明文的网络传输存在安全隐患,因此本节将介绍如何通过生成SSL证书来加密ShellCodeÿ…...

redis windows 版本安装
1. 下载windows安装包并解压 如果是Linux版本可以直接到官网下载,自3.x起官网和微软网站就没有redis安装包更新了,好在github有开发者在编译发布更新(目前最新有5.0.9版本可下),地址:redis windows 5版本下…...

限流算法深入
限流定义及目的 当系统流量达到系统或下游承受能力的阈值时对系统进行限流控制以防止系统或下游挂掉,减少影响面。 限流组成:阈值及限流策略。阈值是指系统单位时间接收到的请求qps总数;限流策略是指限流行业触发后对应的系统行为ÿ…...
java 基础知识 循环的几个题目
1、输出1~100的累加和 结果显示在屏幕,显示在文件res1.txt中 2、输出1-~100的偶数和 结果显示在屏幕,显示在文件res2.txt中 3、输出所有水仙花数: 100~999的数中出现个位数的立方十位数的立方百位数的立方这个数本身 4、输出由9行9列星号组成…...
Spring Boot使用LocalDateTime、LocalDate作为入参
0x0 背景 项目中使用LocalDateTime系列作为dto中时间的类型,但是spring收到参数后总报错,为了全局配置时间类型转换,尝试了如下3中方法。 注:本文基于Springboot2.0测试,如果无法生效可能是spring版本较低导致的。PS&…...

第七周第七天学习总结 | MySQL入门及练习学习第二天
实操练习: 1.创建一个名为 cesh的数据库 2.在这个数据库内 创建一个名为 xinxi 的表要求该表可以包含:编号,姓名,备注的信息 3.为 ceshi 表 添加数据 4.为xinxi 表的数据设置中文别名 5.查询 在 xinxi 表中编号 为2 的全部…...
【考研数学】线形代数第三章——向量 | 3)向量组秩的性质、向量空间、过渡矩阵
文章目录 引言三、向量组等价、向量组的极大线性无关组与秩3.2 向量组秩的性质 四、 n n n 维向量空间4.1 基本概念4.2 基本性质 写在最后 引言 紧接前文学习完向量组秩的基本概念后,继续往后学习向量的内容。 三、向量组等价、向量组的极大线性无关组与秩 3.2 向…...

【技术】SpringBoot Word 模板替换
SpringBoot Word 模板替换 什么是 Word 模板替换如何实现 Word 模板替换 什么是 Word 模板替换 模板一般是具有固定格式的内容,其中一部分需要替换。Word 模板通俗的讲是以 Word 的形式制作模板,固定格式和内容,然后将其中的一部分数据替换掉…...
java jni nv21和nv12互转
目录 libyuv性能比较 NV12 NV21 YUV420格式介绍 jni YUV420toYUV420SemiPlanar java YUV420toYUV420SemiPlanar java NV12toYUV420SemiPlanar jni NV12toYUV420SemiPlanar...
后端面试话术集锦第二篇:spring boot面试话术
🚗后端面试集锦目录 💖后端面试话术集锦第一篇:spring面试话术💖 💖后端面试话术集锦第二篇:spring boot面试话术💖 💖后端面试话术集锦第三篇:spring cloud面试话术💖 💖后端面试话术集锦第四篇:ElasticSearch面试话术💖 💖后端面试话术集锦第五篇:r…...
Doris中分区和分桶使用教程
1 分区与分桶 Doris中有两层的数据划分,第一层是分区(Partition),第二层是分桶(Bucket), Partition又能分为Range分区和List分区。 Bucket仅支持Hash方式。 1.1 Partition 只能指定…...

电脑不安装软件,怎么将手机文件传输到电脑?
很多人都知道,AirDroid有网页版(web.airdroid.com)。 想要文件传输,却不想在电脑安装软件时,AirDroid的网页版其实也可以传输文件。 然而,要将文件从手机传输文件到网页端所在的电脑时,如果按…...
vue3 publish 出现的问题
vue3项目使用 yarn build 编译出dist文件, 发布后出现错误 #问题与解决 1)登录迭代错误(Maximum call stack size exceeded) >deepclone 的问题 在 GrandhallLayout 中判断菜单和权限中; const mainMenu cloneDeep(router.getRoutes()) lodash.clonedee…...

网络防御和入侵检测
网络防御和入侵检测是维护网络安全的关键任务,可以帮助识别和阻止未经授权的访问和恶意行为。以下是一些基本的步骤和方法,用于进行网络防御和入侵检测。 网络防御: 防火墙设置: 部署防火墙来监控和控制网络流量,阻止…...

【科研论文配图绘制】task5 SciencePlots绘图包入门
【科研论文配图绘制】task5 SciencePlots绘图包入门 task5主要学习了SciencePlots拓展包的出图样式,掌握SciencePlots的安装及具体使用。 SciencePlots作为一个专门用于科研论文绘图的第三方拓展工具包,提供了主流英文科技 期刊(如 Nature、Science 和 …...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...

DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...

【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
高防服务器价格高原因分析
高防服务器的价格较高,主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因: 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器,因此…...