数据库(database): 存放数据的仓库, 存放的是一张的表, 特别像excel, numbers, 都以表格的形式存放数据, 可以创建多张表。
常见的数据库: sqlite, mysql, sqlserver, oracle, access。
使用数据库,主要是因为文件读写和归档读取数据需要一次把数据全部读出来, 占用内存开销大;其次是数据库数据效率高, 体现在增删改查。
数据库存储数据的步骤
1、新建一个数据库
2、新建一张表(table)
3、添加多个字段(column,列,属性)
4、添加多行记录(row,每行存放多个字段对应的值)
数据库的操作语句 (增删改查),即sql(structured query language)
sql 语句不区分大小写, 字符串需要加或''
常用语法:(主键: 是一条数据的唯一标示符, 一张表只能有一个主键, 主键不能够重复, 一般把主键名设为id, 不需要赋值, 会自增;*代表所有的字段;where是条件)
1 表操作
(1)创建表: creat table 表名 (字段名字段数据类型 是否为主键, 字段名 字段数据类型, 字段名 字段数据类型...)
(2)修改表名:alter table 旧表名 rename to 新表名
(3)删除表:drop table 表名
(4)表添加一列:alter table 表名 add column 列名数据类型 限定符
2 表数据操作
(1)查: select 字段名 (或者*) from 表名 where 字段名 = 值
(2)加: insert into 表名 (字段1, 字段2...) values (值1, 值2...)
(3)改: update 表名 set 字段 = 值 where 字段 = 值
(4)删: delete from 表名 where 字段 = 值
sqlite是一款轻型的嵌入式数据库,它占用资源非常的低,在嵌入式设备中,可能只需要几百k的内存就足够了。它的处理速度比mysql、postgresql这两款著名的数据库都还快。
sqlite名词解释
2个重要结构体
1 sqlite3 *pdb(数据库句柄,跟文件句柄file类似)
2 sqlite3_stmt *stmt(这个相当于odbc的command对象,用于保存编译好的sql语句)
5个主要函数
1 sqlite3_open()(打开数据库)
2 sqlite3_exec()(执行非查询的sql语句)
3 sqlite3_prepare()(准备sql语句,执行select语句或者要使用parameterbind时,用这个函数(封装了sqlite3_exec))
4 sqlite3_step()(在调用sqlite3_prepare后,使用这个函数在记录集中移动)
5 sqlite3_close()(关闭数据库文件)
sqlite 存储类
1 null(值是一个 null 值)
2 integer(值是一个带符号的整数,根据值的大小存储在1、2、3、4、6 或 8 字节中)
3 real(值是一个浮点值,存储为 8 字节的 ieee 浮点数字)
4 text (值是一个文本字符串,使用数据库编码(utf-8、utf-16be 或 utf-16le)存储)
5 blob (值是一个 blob 数据,完全根据它的输入存储)
sqlite常用语句
1、打开数据库 sqlite3_open函数
2、预处理sql语句sqlite3_prepare_v2函数
3、绑定参数sqlite3_bind_text函数
4、执行sql语句sqlite3_step函数(状态:*sqlite_busy-数据库被锁定、*sqlite_done-成功执行过程、*sqlite_row-返回一行结果、*sqlite_error-运行错误、*sqlite_misuse-错误的使用了本函数)
5、提取字段数据sqlite3_column_text、sqlite3_column_blob、sqlite3_column_int等函数
6、释放statement对象资源 sqlite3_finalize函数
7、关闭数据库 sqlite3_close函数
sqlite的使用
1、在ios中使用sqlite时,首先需要添加库文件libsqlite3.tbd
2、导入主头文件 #import
3、数据库操作(注:设置数据库名称及路径)
示例代码:
设置数据库路径
- (void)setsqlitepath
{
if (self.filepath == nil)
{
// document目录下
nsarray *documentarray =nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask,yes);
nsstring *document = [documentarray objectatindex:0];
_filepath = [document stringbyappendingpathcomponent:sqlitefile];
}
nslog(@filepath %@, _filepath);
}
打开数据库,创建表
- (void)new
{
nsstring *sql = @create table if not exists student(name textprimary key, address text, phone text);
if (sql && 0 != sql.length)
{
[self setsqlitepath];
if ([[nsfilemanager defaultmanager] fileexistsatpath:self.filepath])
{
// 打开数据库
sqlite3 *database; // sqlite3
const char *filename = [self.filepath utf8string]; // [xxx utf8string]是将nsstring转换为c字符串,因为sqlite3是采用可移植的c(而不是 objective-c)编写的,它不知道什么是nsstring.
int openstatus = sqlite3_open(filename, &database);
if (openstatus != sqlite_ok)
{
// 数据库打开失败,关闭数据库
sqlite3_close(database);
nsassert(0, @打开数据库失败);
nslog(@打开数据库失败);
}
nslog(@打开数据库成功);
// 创建表
char *errormsg;
const char *execsql = [sql utf8string];
int execstatus = sqlite3_exec(database,execsql, null, null, &errormsg);
if (execstatus != sqlite_ok)
{
// 创建表失败,关闭数据库
sqlite3_close(database);
nsassert1(0, @创建表失败:%s,errormsg);
}
nslog(@创建表成功);
}
}
}
插入数据
- (void)insert
{
// ?号表示一个未定的值
nsstring *sql = @insert or replace into student (name, address,phone) values (?,?,?);
if (sql && 0 != sql.length)
{
[self setsqlitepath];
if ([[nsfilemanager defaultmanager] fileexistsatpath:self.filepath])
{
// 打开数据库
sqlite3 *database; // sqlite3
const char *filename = [self.filepath utf8string];
int openstatus = sqlite3_open(filename,&database);
if (openstatus != sqlite_ok)
{
// 数据库打开失败,关闭数据库
sqlite3_close(database);
nsassert(0, @打开数据库失败);
nslog(@打开数据库失败);
}
nslog(@打开数据库成功);
const char *execsql = [sql utf8string];
sqlite3_stmt *statment;
int execstatus = sqlite3_prepare_v2(database, execsql, -1,&statment, nil); // 接口把一条sql语句解析到statement结构里去. 使用该接口访问数据库是当前比较好的的一种方法
if (execstatus == sqlite_ok)
{
nslog(@插入更新表成功);
// 绑定参数开始
// 这里的数字1,2,3代表上面的第几个问号,这里将三个值绑定到三个绑定变量
sqlite3_bind_text(statment, 1,[@zhangshaoyu utf8string], -1, null);
sqlite3_bind_text(statment, 2,[@meizhou utf8string], -1, null);
sqlite3_bind_text(statment, 3,[@13800138000 utf8string], -1, null);
// 执行sql语句 执行插入
if (sqlite3_step(statment) !=sqlite_done)
{
nsassert(no, @插入更新表失败。);
}
else
{
nslog(@插入更新表成功);
}
}
else
{
nslog(@插入更新表失败);
}
// 释放sqlite3_stmt对象资源
sqlite3_finalize(statment);
// 关闭数据库
sqlite3_close(database);
}
}
}
修改更新数据
- (void)update
{
nsstring *sql = @update student set address = ? where name =?;
if (sql && 0 != sql.length)
{
[self setsqlitepath];
if ([[nsfilemanager defaultmanager]fileexistsatpath:self.filepath])
{
// 打开数据库
sqlite3 *database; // sqlite3
const char *filename = [self.filepath utf8string];
int openstatus = sqlite3_open(filename, &database);
if (openstatus != sqlite_ok)
{
// 数据库打开失败,关闭数据库
sqlite3_close(database);
nsassert(0, @打开数据库失败);
nslog(@打开数据库失败);
}
nslog(@打开数据库成功);
const char *execsql = [sql utf8string];
sqlite3_stmt *statment;
int execstatus = sqlite3_prepare_v2(database, execsql, -1,&statment, nil);
if (execstatus == sqlite_ok)
{
nslog(@更新表成功);
// 绑定text类型的数据库数据
// 这里的数字1,2,3代表第几个问号。这里只有1个问号,这是一个相对比较简单的数据库操作,真正的项目中会远远比这个复杂
sqlite3_bind_text(statment, 1,[@meizhouwuhua utf8string], -1, null);
sqlite3_bind_text(statment, 2,[@zhangshaoyu utf8string], -1, null);
// 执行插入
if (sqlite3_step(statment) !=sqlite_done)
{
nsassert(no, @更新表失败。);
}
else
{
nslog(@更新表成功);
}
}
else
{
nslog(@更新表失败);
}
// 释放sqlite3_stmt对象资源
sqlite3_finalize(statment);
// 关闭数据库
sqlite3_close(database);
}
}
}
查找数据
- (void)select
{
nsstring *sql = @select * from student;
if (sql && 0 != sql.length)
{
[self setsqlitepath];
if ([[nsfilemanager defaultmanager] fileexistsatpath:self.filepath])
{
// 打开数据库
sqlite3 *database; // sqlite3
const char *filename = [self.filepath utf8string];
int openstatus = sqlite3_open(filename, &database);
if (openstatus != sqlite_ok)
{
// 数据库打开失败,关闭数据库
sqlite3_close(database);
nsassert(0, @打开数据库失败);
nslog(@打开数据库失败);
}
nslog(@打开数据库成功);
const char *execsql = [sql utf8string];
sqlite3_stmt *statment;
int execstatus = sqlite3_prepare_v2(database, execsql, -1,&statment, nil);
if (execstatus == sqlite_ok)
{
nslog(@查询成功);
// 查询成功,执行遍历操作
// 查询结果集中一条一条的遍历所有的记录,这里的数字对应的是列值,注意这里的列值,跟上面sqlite3_bind_text绑定的列值不一样!一定要分开,不然会crash,只有这一处的列号不同,注意!
while(sqlite3_step(statment) ==sqlite_row)
{
const char *name = (char*)sqlite3_column_text(statment, 0);
if (name != null)
{
nsstring *name =[[nsstring alloc] initwithutf8string:name];
nslog(@name%@, name);
}
char *address = (char*)sqlite3_column_text(statment, 1);
if (address != null)
{
nsstring *address =[[nsstring alloc] initwithutf8string:address];
nslog(@address%@, address);
}
char *phone = (char*)sqlite3_column_text(statment, 2);
if (phone != null)
{
nsstring *phone =[[nsstring alloc] initwithutf8string:phone];
nslog(@phone%@, phone);
}
}
}
else
{
nslog(@查询失败);
}
// 释放sqlite3_stmt对象资源
sqlite3_finalize(statment);
// 关闭数据库
sqlite3_close(database);
}
}
}
删除数据
- (void)delete
{
//nsstring *sql = @delete from student; // 方法1
nsstring *sql = @delete from student where name = ?; // 方法2
if (sql && 0 != sql.length)
{
[self setsqlitepath];
if ([[nsfilemanager defaultmanager] fileexistsatpath:self.filepath])
{
// 打开数据库
sqlite3 *database; // sqlite3
const char *filename = [self.filepath utf8string];
int openstatus = sqlite3_open(filename,&database);
if (openstatus != sqlite_ok)
{
// 数据库打开失败,关闭数据库
sqlite3_close(database);
nsassert(0, @打开数据库失败);
nslog(@打开数据库失败);
}
nslog(@打开数据库成功);
const char *execsql = [sql utf8string];
sqlite3_stmt *statment;
int execstatus = sqlite3_prepare_v2(database, execsql, -1, &statment,nil);
if (execstatus == sqlite_ok)
{
// 绑定text类型的数据库数据
// 这里的数字1,2,3代表第几个问号。这里只有1个问号,这是一个相对比较简单的数据库操作,真正的项目中会远远比这个复杂
sqlite3_bind_text(statment, 1,[@zhangshaoyu utf8string], -1, null);
// 执行删除
if (sqlite3_step(statment) !=sqlite_done)
{
nsassert(no, @删除数据失败。);
nslog(@删除数据失败);
}
else
{
nslog(@删除数据成功);
}
}
else
{
nslog(@删除数据失败);
}
// 释放sqlite3_stmt对象资源
sqlite3_finalize(statment);
// 关闭数据库
sqlite3_close(database);
}
}
}
删除表
- (void)deletetable
{
nsstring *sql = @drop table student;
if (sql && 0 != sql.length)
{
[self setsqlitepath];
if ([[nsfilemanager defaultmanager] fileexistsatpath:self.filepath])
{
// 打开数据库
sqlite3 *database; // sqlite3
const char *filename = [self.filepath utf8string];
int openstatus = sqlite3_open(filename, &database);
if (openstatus != sqlite_ok)
{
// 数据库打开失败,关闭数据库
sqlite3_close(database);
nsassert(0, @打开数据库失败);
nslog(@打开数据库失败);
}
nslog(@打开数据库成功);
const char *execsql = [sql utf8string];
sqlite3_stmt *statment;
int execstatus = sqlite3_prepare_v2(database, execsql, -1,&statment, nil);
if (execstatus == sqlite_ok)
{
// 执行删除
if (sqlite3_step(statment) !=sqlite_done)
{
nsassert(no, @删除表失败。);
nslog(@删除表失败);
}
else
{
nslog(@删除表成功);
}
}
else
{
nslog(@删除表失败);
}
// 释放sqlite3_stmt对象资源
sqlite3_finalize(statment);
// 关闭数据库
sqlite3_close(database);
}
}
}
数据查看
注意事项:
1、由于sqlite3是基于c语言编写的,而不是纯粹的object-c,所以有关字符串,我们不能使用nsstring,因为它不识别,所以只能用c语言的字符串,char*,好在nsstring提供了转换的方法,那就是 utf8string。如:
nsstring*sql = @delete from student where name = ?;
constchar *execsql = [sql utf8string];
2、sql语句中,不确定值使用?符号。如:
nsstring*sql = @delete from student where name = ?;
3、提取查询数据函数中的数字表示sql语句中的第几列(0~n)。如:
表示第1列:constchar *name = (char *)sqlite3_column_text(statment, 0);
4、绑定数据时函数中的数字表示sql语句中的第几个值。如:
nsstring*sql = @insert or replace into student (name, address, phone) values(?,?,?);
表示第1个值:sqlite3_bind_text(statment,1, [@zhangshaoyu utf8string], -1, null);
表示第2个值:sqlite3_bind_text(statment,2, [@meizhou utf8string], -1, null);
表示第3个值:sqlite3_bind_text(statment,3, [@13510213244 utf8string], -1, null);
5、创建表时,必须设置一个主键primary key。如:
nsstring*sql = @create table if not exists student(name text primary key, addresstext, phone text);