网站开发价格预算,做音响的是哪个网站,百度搜索页面,wordpress 地图html代码永久存储程序数据有两种方式#xff1a;
用文件存储用数据库存储
对于多条记录的存储而言#xff0c;采用文件时#xff0c;插入、删除、查找的效率都会很差#xff0c;为了提高这些操作的效率#xff0c;有计算机科学家设计出了数据库存储方式 一、数据库
数据库的基本…永久存储程序数据有两种方式
用文件存储用数据库存储
对于多条记录的存储而言采用文件时插入、删除、查找的效率都会很差为了提高这些操作的效率有计算机科学家设计出了数据库存储方式 一、数据库
数据库的基本组成
用来管理数据库的软件被称数据库管理系统
一个数据库管理系统管理着多个数据库
一个数据库中可以包含很多张表
一张表中拥有很多记录(行)
一条记录拥有很多字段(列)
每条记录的每个字段存放不同类型的数据
因此数据库本质上是表的集合 数据库按数据的组织形式分为
关系型数据库 ----- 本章内容非关系型数据库
数据库管理系统软件按是否支持远程分为
网络版 ---- MySql Oracle SQlServer单机版 ---- sqlite 网络版的数据管理系统的整体框架 数据库管理系统发展初期各家开发此类软件的公司采用的通信协议是不同的这给应用客户端开发造成很大的麻烦
因此经过一段时间的发展全球几家著名的数据库管理系统开发公司制定了统一的通信协议这个统一的通信协议被称为SQL(Structure Query Language)
随着关系型数据库的不断发展SQL成为所有数据库管理系统的统一协议
每个数据库管理系统都会提供一个命令行界面的简易客户端应用程序员可以使用这个简易客户端学习、练习SQL语句以及辅助开发
每一条SQL语句就是一个操作请求 二、SQLite
一个单机版的数据库管理系统
所有操作请求也遵循SQL标准
开源、精悍
SQLite安装
1.安装SQLite3
命令行下输入sudo apt-get install sqlite32.安装SQLite3编译需要的工具包
命令行下输入 sudo apt-get install libsqlite3-dev如出现问题尝试
sudo dpkg --purge --force-depends libsqlite3-0
sudo apt-get install libsqlite3-0
sudo apt-get install -f
sudo apt-get install libsqlite3-dev
sudo apt-get install sqlite3
支持三种字段数据类型
INTEGER 或 INT 值是一个带符号的整数根据值的大小存储在 1、2、3、4、6 或 8 字节中。REAL 值是一个浮点值存储为 8 字节的 IEEE 浮点数字。TEXT 值是一个文本字符串单引号或双引号括起的字符串
使用数据库编码UTF-8、UTF-16BE 或 UTF-16LE存储 三、sqlite3简易客户端的使用
1. 运行
Linuxsqlite3 ------ 只是进入sqlite3的命令行界面不创建打开任何数据库
Linuxsqlite3 路径/数据库文件名 ----- 先创建打开指定的数据库然后进入sqlite3的命令行界面
sqlite3管理的一个数据库在Linux系统下用一个文件表示它习惯上将这个文件命名为 xxx.db
2. 两种命令 . 开头的命令简易客户端的内部命令 以 ; 结尾的命令; 前的内容为SQL语句; 是简易客户端要求的结尾符
3. 常用内部命令
创建打开一个指定的数据库
sqlite .open 路径/xxx.db
sqlite .help查看正在使用的数据库
sqlite .databasesSQL语句操作结果按列对齐 ----- 重要
sqlite .mode column 显示某表时是否显示表头 ----- 重要
sqlite .headers on/off显示数据中的表 ------ 重要
sqlite .tables退出sqlite命令行 ---- 重要
sqlite .quit 四、常用SQL语句
SQL语句组成关键字 运算符 字段名或表名 常量
SQL语句的关键字可以全大写、也全小写、甚至可以大小混合一般建议采用全大写
字段名或表名的大小是区分的aaa、Aaa、AAA认为是不同的字段名或表名自建表建议字段名或表名全小写
1. 建表
CREATE TABLE [IF NOT EXISTS] table_name(column_name1 datatype[(size)] [PRIMARY KEY] [AUTOINCREMENT] [NOT NULL],column_name2 datatype,column_name3 datatype,.....column_nameN datatype,
);
[]表示可选选用时不带[]
[AUTOINCREMENT]:只能用于INTEGER 表示如果插入新记录时没有指定该字段的值则其值为前一条记录同字段值1
[PRIMARY KEY]:主键,唯一标识表中的记录 主键表中每条记录的该字段值不会重复也即该字段值可以唯一标识一条记录
[IF NOT EXISTS]如果表不存在则建表如果存在则什么都不做
[NOT NULL]:表示字段内容不能为空示例
sqlite CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,... name TEXT,sex TEXT(1),score REAL); 2. 删表
DROP TABLE 表名;示例
sqlite CREATE TABLE ttt(xxx TEXT,yyy TEXT);
sqlite DROP TABLE ttt;3. 插入新记录
通用
INSERT INTO table_name(column1, column2,...columnN) VALUES(value1, value2,...valueN);不缺字段时
INSERT INTO table_name VALUES(value1,value2,...valueN); 4. 查询记录
SELECT column1, column2, columnN FROM table_name [WHERE condition];
SELECT * FROM table_name [WHERE condition];
*表示查询结果显示所有字段
无WHERE子句则查询所有记录5. where子句
所谓子句就是不能成为独立的SQL语句只能成为一条SQL语句的一部分WHERE子句用来为一些操作指定条件
WHERE conditioncondition可以是单个条件或由AND、OR连接的多个条件比较运算符支持:! 用法字段名 运算符 值IN()用法字段名 IN(值1,值2,...,值n) 表示字段值为值1或值2或....NOT IN()用法字段名 NOT IN(值1,值2,...,值n) 表示字段值不为值1也不为值2也不为....LIKE用法字段名 LIKE 模式字串 模式字串中可以用%号表示任意多个字符用_表示单个字符默认不区分大小写GLOB用法字段名 GLOB 模式字串 模式字串中可以用*号表示任意多个字符用?表示单个字符区分大小写IS NOT NULL用法字段名 IS NOT NULL 判断字段值是否为空IS NULL用法字段名 IS NULL 判断字段值是否为空BETWEEN AND用法字段名 BETWEEN 值1 AND 值2 字段值值1 且 字段值值2NOT反条件用法字段名 NOT 其它条件6. 修改记录
UPDATE table_name SET column1 value1, column2 value2...., columnN valueN WHERE [condition];
无WHERE子句则对所有记录进行修改7. 删除记录
DELETE FROM table_name WHERE [condition];
无WHERE子句则删除所有记录8. Sort子句
ORDER BY 字段名 ASC 或 DESC
ASC升序
DESC降序9. SQL语句中的函数
datetime(now,localtime) ---- 产生当前日期时间的字符串使用示例
INSERT INTO Table_name VALUES(datetime(now,localtime));count(*) 对查询结果求记录数
使用示例
SELECT count(*) FROM student; 五、sqlite3函数库
SQL按执行完毕后是否有记录结果分为两种
一种SQL语句的执行只论是否成功。例如建表、删表、插入记录、修改记录、删除记录
另一种SQL语句执行完毕产生多条记录结果。例如查询
sqlite3_open参照图 sqlite3_exec及其回调函数的参考图 sqlite3_get_table函数参考图1 //头文件包含
#include sqlite3.h/*链接选项-lsqlite3
*///1、打开/创建一个数据库
int sqlite3_open(const char *filename, sqlite3 **ppDb );
/*
功能打开指定的数据库如果数据库并存在则创建并打开指定的数据库并创建一个后续操作该数据库的引擎
参数filename带路径的数据库文件名ppdb指向sqlite句柄的指针,调用前定义一个sqlite3 *指针变量取该指针变量的地址
返回成功 SQLITE_OK 值为0,否则返回其他值。
*///2、如果打开数据库失败open函数只是返回错误码如果想要错误原因的字符串描述则调用该函数
const char *sqlite3_errmsg(sqlite3 *db);
/* 返回值返回错误信息
*///3、回调函数执行sql语句
//更加适用于sql语句执行没有记录结果的情况(此时第3、4参数填NULL)或对需要依次对每条操作结果记录进行处理的情况
int sqlite3_exec(sqlite3* pDB, const char *sql, sqlite_callback callback, void*para, char** errMsg);/*
功能执行SQL语句查询的结果返回给回调函数callback多个结果的操作每个结果都会调用一次callback
参数pDB数据库引擎的句柄。sql待执行的SQL 语句字符串以’\0’结尾不以;结尾。callback回调函数用来处理查询结果如果不需要回调比如做insert 或者delete 操作时可以置NULL。para要传入回调函数的指针参数没有可以置为NULL。errMsg一级指向空间存放着一个char *类型的元素该元素指向空间(二级指向空间)存放着一个字符串该字符串内容描述出错原因因此1. 调用前定义一个char *类型的指针变量传该指针变量的地址给该形参。2. 由于其二级指向空间是动态分配的因此使用完后需要调用sqlite3_free函数进行释放;
返回值执行成功返回SQLITE_OK否则返回其他值
*///4、回调函数
typedef int (*sqlite_callback)(void* para, int columnCount, char** columnValue,char** columnName);
/*
功能由用户处理查询的结果每找到一条记录自动执行一次回调函数
参数para从sqlite3_exec()传入的参数指针columnCount查询到的这一条记录有多少个字段(即这条记录有多少列)columnValue查询出来的数据都保存在这里它实际上是个1 维数组不要以为是2 维数组每一个元素都是一个char * 值是一个字段内容用字符串来表示以‘\0’结尾columnName与columnValue 是对应的表示这个字段的字段名称。
返回值执行成功返回SQLITE_OK否则返回其他值
*///5、关闭
int sqlite3_close(sqlite3 *ppDb);
/*
功能关闭sqlite数据库。
参数ppdb数据库句柄。
返回值成功返回0失败返回错误码
*///6、释放
void sqlite3_free(void * errMsg );
/*
功能释放存放错误信息的内存空间
参数errMsg: 返回错误信息
*///7、非回调来执行sql语句
//更加适用于SQL语句执行后有一条或多条记录结果且程序期望对所有记录结果的整体进行处理的情况
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 */);/*
功能非回调来执行sql语句
参数db:数据库句柄zSql要执行的SQL语句pazResult查询结果一维数组,定义一个char **的二级指针变量调用函数时传该二级指针变量的地址不使用应立即调用sqlite3_free_table(result)进行释放pnRow查询出多少条记录查出多少行 不包括字段名所在行pnColumn多少个字段查出多少列pzErrmsg错误信息
返回值执行成功返回SQLITE_OK否则返回其他值
注pazResult的字段值是连续的是一维数组不是二维数组从第0索引到第 pnColumn- 1索引都是字段名称从第 pnColumn索引开始后面都是字段值。
*///8、释放pazResult查询结果
void sqlite3_free_table(char **pazResult);
/*参数pazResult指向空间存放着查询结果指向空间为元素类型是char *的一维数组
*/ 示例代码
#include stdio.h
#include sqlite3.hint handle_a_record(void *para,int cols,char **ppval,char **ppname);int main(){sqlite3 *pdb NULL;int ret 0;ret sqlite3_open(./test.db,pdb); // openif(ret ! SQLITE_OK){printf(sqlite3 not open,because %s\n,sqlite3_errmsg(pdb));sqlite3_close(pdb);pdb NULL;return 1;}{char sql[80] ;char *perr NULL;sprintf(sql,SELECT * FROM stu); // write instructionret sqlite3_exec(pdb,sql,handle_a_record,NULL,perr); // exec()if(ret ! SQLITE_OK){ // errorprintf(exec %s failed,because %s\n,sql,perr);sqlite3_free(perr); // sqlite3_free()perr NULL;}}{char sql[80] ;char *perr NULL;char **ppret NULL;int rows 0;int cols 0;int i 0;int j 0;sprintf(sql,SELECT * FROM stu); // write instructionret sqlite3_get_table(pdb,sql,ppret,rows,cols,perr); // exec()if(ret ! SQLITE_OK){ // errorprintf(exec %s failed,because %s\n,sql,perr);sqlite3_free(perr); // sqlite3_free()perr NULL;}else{for(j 0;j cols;j){printf(%-20s ,*(ppret j));}printf(\n);}for(i 1;i rows;i){for(j 0;j cols;j) printf(%-20s ,*(ppret i * cols j));printf(\n);}sqlite3_free_table(ppret);ppret NULL;
}sqlite3_close(pdb); // sqlite3_close()pdb NULL;return 0;}int handle_a_record(void *para,int cols,char **ppval,char **ppname){int i 0;for(i 0;i cols;i){printf(%s | ,*(ppval i));}printf(\n);return SQLITE_OK;
}输出 六、sqlite3函数库的并发模式
单线程模式 ----- 无锁模式串行模式 ------ 默认模式非阻塞互斥锁实现读者写者模式 ------ 读写锁实现
配置sqlite3函数库的并发模式可以通过1. 重新编译sqlite3函数库的源码 2.调用相关的接口函数进行配置
实际项目中大部分情况采用其默认模式 串行模式时需要对sqlite3_exec、sqlite3_get_table函数进行如下形式的二次封装
int my_sqlite3_exec(sqlite3* pdb, const char *sql, sqlite_callback callback, void*para, char** errmsg){int ret 0; do {ret sqlite3_exec( pdb , sql, callback , para , errmsg ); if (ret SQLITE_BUSY || ret SQLITE_LOCKED){usleep(30 * 1000);continue;}else{break;}} while(1); return ret;
}int my_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 */){int ret 0;do {ret sqlite3_get_table(db,zSql,pazResult,pnRow,pnColumn,pzErrmsg); if (ret SQLITE_BUSY || ret SQLITE_LOCKED){usleep(30 * 1000);continue;}else{break;}} while(1); return ret;
} 七、二次封装
实际项目代码中直接调用sqlite3函数库中的函数实现相关功能会很不方便往往会将项目中可能用到的所有数据库操作代码单独作为一个模块该模块又按表分为几个子模块(一般命名为xxxhelper)由这个模块及其子模块向其它项目代码提供需要的数据库操作接口。 public子模块不隶属于任何一个helper子模块的操作函数归于本子模块
一般项目中建议采用如下方案
/*一、public子模块 -------- 项目名_db_public.c*/
/*1. 函数功能创建打开数据库然后带IF NOT EXISTS关键字去建表*/
sqlite3 *create_db_engine(const char *pdbfile)
{1. 调用sqlite3_open2. 建表13. 建表2。。。。n1. 建表n成功返回引擎地址失败返回NULL
}/*2. 对sqllite3_exec的二次封装 ------ 见上一节*//*3. 对sqllite3_get_table的二次封装 ------ 见上一节*//*4. destroy_db_engine*/
void destroy_db_engine(sqlite3 *pdb)
{sqlite3_close(pdb);
}/*二、对表1的各种操作函数封装 表1名helper.c*/
int insert_new_record_into_表名(sqlite3 *pdb,.........)
{组织sql语句调用my_sqlite3_exec 或 my_sqlite3_get_table函数执行sql语句。。。。。。
}......???? xxxxx(sqlite3 *pdb,.......)
{通过多次执行sql语句组合完成本函数功能
}/*三、对表2的各种操作函数封装 表2名helper.c*/。。。。。。。。。。。。。。。