其实深度解析:iOS平台下的数据库技术与应用的问题并不复杂,但是又很多的朋友都不太了解,因此呢,今天小编就来为大家分享深度解析:iOS平台下的数据库技术与应用的一些知识,希望可以帮助到大家,下面我们一起来看看这个问题的分析吧!
如果不存在如果不存在
如果存在如果存在
主键主键
自动增量自动增量
非空不能为空
默认默认值常见数据库数据类型
整数整数类型
文本文本
实浮点型
1.2 DDL语句
DDL语句一般用于操作数据表,定义、删除、修改数据表。对应的关键字是:create/drop/alter
SQL语句示例
//1 创建数据表(创建学生表t_student)
如果不存在则创建表t_student(id整型主键自增,姓名文本不为空,年龄整型,分数真实默认60)
//2 删除数据表(删除学生表t_student)
如果存在则删除表s_student
//3 修改数据表
//--3.1 修改数据表名称
更改表t_student 重命名为t_person
//--3.2 添加数据表字段
alter table t_stu add column Telephone Integer
1.3 DML语句
DML语句一般用于操作数据表中的记录。数据表中的添加、删除、修改记录一般称为DML语句。
SQL语句示例
//1条插入记录
插入t_stu(姓名,年龄,分数) 值("chmn",24,100)
//2 删除记录
从t_stu 中删除,其中name="chmn"
从名称为“chmn”的t_stu 中删除
//3 修改记录
update t_stu set Score=99 where name="chmn"
1.4 DQL语句
该语句是查询数据表字段,可以查询多个表
注意:
例如有一个学生表和一个成绩表。学生表中的学号是固定的,是学生表的主键。分数表中也有一个“否”。它的值由学生表中的学号字段决定。然后你需要在分数表中设置一个外键。外键是学生表的学号。
SQL语句示例
//1 查询全部
从t_stu 选择*
//2 多表查询
从t_stu,t_score 选择*,其中t_stu.no=t_score_no
//3 排序依据
select * from t_score order by 分数DESC 降序排列
//4统计count 平均值min max
从t_score 中选择count(*)
从t_score 中选择总和(分数)
//5个分页限制
select * from t_score limit 1,2 //跳过1,取2
select * from t_score limit 3 //跳过0项,取3项
2 代码实现SQL语句
2.1 实现大致步骤
导入框架sqlite3.tdb,导入头文件sqlite3.h创建并打开数据库(sqlite3_open)并执行sql语句( sqlite3_exec)
2.2 代码实现DDL语句
点击屏幕后,打开数据库,创建数据表t_person
//1 打开数据库
//--1.1 数据库路径(后缀名任意,一般为sqlite或db)
让路径="/Users/apple/Pictures/myDb.sqlite"
//--1.2 定义数据库指针指向打开的数据库
var db:COpaquePointer=nil
//--1.3 打开数据库(如果路径不存在则创建后打开)
如果sqlite3_open(路径, db)==SQLITE_OK {
print("数据库打开成功")
}别的{
print("数据库打开失败")
}
//2 创建数据表
//--2.1 获取SQL语句
let sql="如果不存在则创建表t_person(姓名文本,年龄整数)"
//--2.2 执行sql语句
/*
参数1 打开数据库
参数2 需要执行的SQL语句
参数3回调
参数4回调参数
参数5错误信息
*/
如果sqlite3_exec(db, sql, nil, nil, nil)==SQLITE_OK {
print("数据表创建成功")
}别的{
print("数据表创建失败")
}
//3 删除数据表
let deleSql="如果存在t_person 则删除表"
如果sqlite3_exec(db, deleSql, nil, nil, nil)==SQLITE_OK {
print("删除表创建成功")
}别的{
print("删除表创建失败")
一般都是封装成工具类直接使用。
封装工具类SqliteTool.swift
类SqliteTool: NSObject {
//设置单例
静态让shareInstance=SqliteTool()
//定义数据库指针指向打开的数据库
var db:COpaquePointer=nil
重写init() {
超级.init()
/**打开数据库*/
//1 打开数据库
让路径="/Users/apple/Pictures/myDb.sqlite"
//打开数据库(如果路径不存在则创建后打开)
如果sqlite3_open(路径, db)==SQLITE_OK {
print("数据库打开成功")
}别的{
print("数据库打开失败")
}
}
/**执行sql语句*/
func 执行(sql:String) -Bool
{
返回(sqlite3_exec(db,sql,nil,nil,nil)==SQLITE_OK)
}
/**创建表*/
函数创建表()
{
//获取SQL语句
let sql="如果不存在则创建表t_person(姓名文本,年龄整数)"
//执行sql语句
/*
参数1 打开数据库
参数2 需要执行的SQL语句
参数3回调
参数4回调参数
参数5错误信息
*/
如果执行(sql){
print("表创建成功")
}别的{
print("创建表失败")
}
}
/**删除表*/
函数dropTable()
{
//删除数据表
let sql="如果存在t_person 则删除表"
如果执行(sql){
print("删除表成功")
}别的{
print("删除表失败")
}
}
}
2.3 代码实现DML语句
定义Person类,它有两个字段:姓名和年龄。将这个实例对象插入到上面的数据表中,并进行更新等操作。
Person.swift 添加了以下对象方法
2.3.1 插入
/**插入数据表*/
函数插入表()
{
//1条常用sql
let sql="插入t_person(姓名,年龄) 值("(self.name)",(self.age))"
//2 执行sql语句
如果SqliteTool.shareInstance.execute(sql) {
print("插入成功")
}别的{
print("插入失败")
}
}
2.3.2 删除
/**从数据表中删除*/
函数从表中删除()
{
let sql="从t_person 中删除name="(self.name)""
如果SqliteTool.shareInstance.execute(sql){
print("删除成功")
}别的{
print("删除失败")
}
2.3.3 修改
函数updateTable()
{
让sql="更新t_person 设置名称="(self.name)",age=(self.age)"
如果SqliteTool.shareInstance.execute(sql){
print("更新成功")
}别的{
print("更新失败")
}
}
2.3.4 绑定插入
到目前为止,我们使用的插入都是直接使用sqlite_exec 方法实现的。事实上,iOS 提供了准备好的语句来绑定插入。而且,上面的sqlite_exec实际上是对绑定插入的封装。绑定插入实际上就是先提供一个预处理语句,然后绑定预处理语句中的参数来实现插入。一般来说,绑定插入比直接使用sqlite_exec效率更高,因为sqlite_exec也是绑定插入的封装绑定。自定义插入步骤
1、创建一条sql语句,参数用问号表示?
2.根据sql创建准备语句sqlite3_prepare_v2
3、分别绑定参数sqlite3_bind_text sqlite3_bind_int sqlite3_bind_Double。
4.执行准备好的语句sqlite3_step
5.重置准备好的语句sqlite3_reset
6.释放准备好的语句sqlite3_finalize
一般用法:如果插入数据量较大,步骤1/2/7只需要执行一次,中间循环执行步骤3~6,可以提高效率。
/**绑定插入*/
函数绑定插入()
{
//1 创建预备语句——使用可变参数?表达、固定的写法
let db=SqliteTool.shareInstance.db //打开数据库
let zSql="insert into t_person(姓名,年龄,分数)values(?)" //sql语句
var ppStmt : COpaquePointer=nil //生成的处理语句-传入地址
//-参数4,取出字符串zSql的长度。 -1表示自动计算
//-参数5,表示排除参数3指定的长度后zSql的剩余语句
如果sqlite3_prepare_v2(db, zSql, -1, ppStmt, nil) !=SQLITE_OK {
print("预处理失败")
}
//2 绑定整数类型
//-参数1代表上面创建的预编译语句
//-参数2,表示绑定zSql中问号代表的哪个参数是索引。从1 开始
//-参数3,对应参数2的值
sqlite3_bind_int(ppStmt, 2, 24) //绑定年龄=24
//3 绑定浮点类型
sqlite3_bind_double(ppStmt, 3, 89.7) //绑定分数=89.7
//4 绑定文本类型
//-参数1准备好的语句
//-参数2绑定索引
//-参数3需要绑定的值
//-参数4:从参数3中取出数据长度进行绑定,-1表示自动计算
//-参数5 处理参数值有两种方式:
//--------SQLITE_STATIC : 认为参数是常量,不会被释放,也不会进行任何引用。宏0
//--------SQLITE_TRANSIENT: 将引用该参数。这是一个宏,-1
//--------按位转换可以进入头文件查看,因为Swift不能有宏,所以要自己转换
//--------将该宏表示的-1转换为sqlite3_destructor_type类型
让SQLITE_TRANSIENT=unsafeBitCast(-1, sqlite3_destructor_type.self)
sqlite3_bind_text(ppStmt, 1, "zhangsan", -1, SQLITE_TRANSIENT)
//5 执行准备好的语句
如果sqlite3_step(ppStmt)==SQLITE_DONE {
print("执行成功")
}别的{
print("执行失败")
}
//6 重置准备好的语句-重置绑定
sqlite3_reset(ppStmt)
//7 释放准备好的语句
sqlite3_finalize(ppStmt)
}
2.3.5绑定插入(sqlite3_step)与插入(sqlite3_exec)的效率分析
测试方法:
当前执行时间获取方法CFAbsoluteTimeGetCurrent()
1 使用绑定插入循环插入10000条数据,计算插入开始和完成的时间差。
测试时,循环执行上述代码的步骤3~6,计算时间差2、创建插入sql,使用sqlite3_exec插入,计算时间差。
3 比较两种效率
综上所述:
效率上有差异,但差别不大。整体插入大数据需要很长时间,急需优化。
2.3.6 大数据插入的优化
问题的原因
无论是绑定预处理执行(sqlite3_step)还是直接sql执行(sqlite3_exec),在进行大数据操作时都会出现耗时问题。很长的情况。原因:
1 sqlite3_exec是sqlite3_step的封装,效率会比较低
2 当sqlite3_step绑定时,虽然创建并释放了prepared语句,但它们只执行一次。不过,每次执行数据库操作之前,都会先开启一个“事务”,执行完一个操作后,才会提交一个“事务”。当循环执行大量操作时,打开和提交事务的过程需要非常长的时间。这是根本原因。
优化方法
1 使用绑定操作sqlite3_step
2 创建准备好的语句和释放准备好的语句都保证只执行一次。
3 手动开启交易并提交交易
代码
绑定参数前,手动启动事务
让sql="开始事务"
sqlite3_exec(sql) 在结束插入并释放准备好的语句之前手动提交事务
让sql="提交事务"
sqlite3_exec(sql)
2.4 代码实现DQL语句
查询操作也分为两种。一种是直接使用sqlite3_exec执行sql语句查询;另一种是使用sqlite3_step执行预处理语句查询。
2.4.1 sqlite3_exec直接执行sql查询
这时候就需要使用sqlite3_exec的回调方法。每次查询一行时都会调用该回调方法,直到回调方法返回1 或查询完成。回调方法中的参数为:
参数1无意义,由slite3_exec的参数4传入,与context类似参数2查询当前行的列数(字段数)参数3查询当前行的字段值数组-- - sqlite3_exec 方法查询到的所有字段值都被视为文本类型参数4、查询当前行的字段名数组。返回值表示是否终止查询。我们自己控制它。如果返回0,则表示继续查询,直到找到完整的结果;如果返回1,则表示查询终止,不再查询。例子:
fun 查询全部()
{
//1 创建sql语句
让sql="从t_person 选择*"
let db=SqliteTool.shareInstance.db //打开数据库
//2 执行查询语句——每次查询一行数据时都会调用该回调方法
sqlite3_exec(db,sql,{(firstValue,columnCount,columnValues,columnNames)-Int32 in
//遍历当前行的所有字段(列)
让计数=Int(列数)
for i in 0. 相当于UnsafeMutablePointer,也相当于char * 指向字符串
让列名=列名[i]
//---转换为字符串
让columnNameStr=String(CString:columnName,encoding: NSUTF8StringEncoding)
//获取当前字段的值
让列值=列值[i]
让columnValues=String(CString:columnValue,encoding: NSUTF8StringEncoding)
打印(列名Str,列值)
}
return 0 //如果返回0,表示继续查询,直到查询结束;如果返回1,则表示查询将在当前位置终止。
},无,无)
}
2.4.2 sqlite3_step执行预处理语句查询
主要步骤与绑定插入相同。首先,创建准备好的语句,再次绑定该语句,然后执行该语句,然后重置该语句,最后释放该语句。
执行的结果集需要我循环获取。它获取的结果集不仅仅是文本类型,而是可以根据数据库中实际存储的类型进行解析。
例子:
函数prepareQuaryAll()
{
让sql="从t_person 选择*"
让db=SqliteTool.shareInstance.db
var stmt : COpaquePointer=nil
//创建准备好的语句
如果sqlite3_prepare_v2(db, sql, -1, stmt, nil) !=SQLITE_OK {
print("预处理失败")
返回
}
//Binding - 如果没有需要绑定的参数可以省略
//执行prepared statements——每次执行都是一行数据,每行记录(结果集)都放在stmt中
而sqlite3_step(stmt)==SQLITE_ROW {
//获取当前行有多少列(字段)
让columnCount=sqlite3_column_count(stmt)
//循环出每个字段
对于0 中的i.(值)
让valueStr=String(CString: valueInt8,encoding: NSUTF8StringEncoding)
print(列名Str,值Str)
}else if type==SQLITE_INTEGER{ //如果是整数
让值=sqlite3_column_int(stmt,i)
打印(列名Str,值)
}else if type==SQLITE_FLOAT { //如果是浮点类型
让值=sqlite3_column_double(stmt,i)
打印(列名Str,值)
}
}
}
}
3 事务Transaction(批量操作的优化)
事务是并发控制的单位和用户定义的操作序列。事务中的所有操作要么完成,要么什么都不完成。事务是一个完整的工作单元。通过事务,可以将一些逻辑上相关的操作绑定在一起。事务通常以开始事务开始,以提交事务或回滚事务结束。当执行大量操作时,默认每个操作都会开启一个事务(成功后提交事务,失败后回滚事务)。频繁的开启交易操作会耗费大量的时间。当进行大量操作时,我们将这些操作放在一个事务中,整体只开启一个事务。交易成功后提交。失败后回滚事务以提高效率。示例:将插入的语句放入事务中并执行
函数插入操作()
{
//创建插入sql
let sql1="insert into t_stu(name,age) values("chenhua",23)" //数据库存在
let sql2="insert into t_stu2(name,age) values("lisi",24)" //数据库不存在
///开启交易
SqliteTool.shareInstance.execute("开始事务")
//执行操作
让result1=SqliteTool.shareInstance.execute(sql1)
让result2=SqliteTool.shareInstance.execute(sql2)
//判断结果并处理交易
如果结果1 结果2 {
打印("提交")
SqliteTool.shareInstance.execute("提交事务")
}别的{
print("回滚")
SqliteTool.shareInstance.execute("回滚事务")
}
4 FMDB框架的使用
是一个面向对象的SQLite框架,封装了sqlite。所以导入框架后需要添加框架依赖sqlite3.0.tdb
4.1 创建数据库并打开
让路径="/Users/apple/Desktop/haha/fmdb.sqlite"
//打开数据库
让db=FMDatabase(path: 路径)
db.open()
4.2 创建数据表
//创建数据表
let tableSql="如果不存在则创建表t_student(姓名文本,年龄整数,分数真实)"
如果db.executeStatements(tableSql) {
print("数据表创建成功")
}别的{
print("创建数据表失败")
}
4.3 更新数据(增删改使用executeUpdate方法)
//更新数据(executeUpdate用于增删改查)
let insertSql="插入t_student(姓名,年龄,分数)values("jim",23,22)"
如果db.executeUpdate(insertSql, withArgumentsInArray: nil) {
print("数据插入成功")
}别的{
print("插入数据失败")
}
4.4 查询数据(使用executeQuery方法)
//查询数据--查询结果放入结果集中
让querySql="从t_student中选择*"
让resultSet=db.executeQuery(querySql, withArgumentsInArray: nil)
//---循环检索里面的记录
while resultSet.next() {
//获取当前行的字段数(列数)
让columnCount=resultSet.columnCount()
//获取指定字段的值
让name=resultSet.stringForColumn("name")
让年龄=resultSet.intForColumn("age")
让分数=resultSet.doubleForColumn("分数")
print(姓名,年龄,成绩)
}
4.5 执行事务
//开始事务
db.beginTransaction()
//执行操作
let insertSql1="插入t_student(姓名,年龄,分数)values("jim",23,22)"
let insertSql2="插入t_student2(姓名,年龄,分数)values("jim",23,22)"
让result1=db.executeUpdate(insertSql1, withArgumentsInArray: nil)
让result2=db.executeUpdate(insertSql2, withArgumentsInArray: nil)
//提交或回滚事务
如果结果1 结果2
{
db.commit()
}别的{
db.rollback()
}
4.6 预处理语句
与正常状态相同。是的,您需要使用标准语法。用问号吗?代表参数
4.7 线程安全的操作数据库
无法直接使用FMDataBase打开数据库然后执行操作。您需要使用FMDatabaseQueue类,它在回调块中提供db
//创建数据库队列
让dbQueue=FMDatabaseQueue(path: 路径)
//对数据库进行操作
dbQueue.inDatabase { (db:FMDatabase!) - 无效
//使用db进行相应的增删改查操作
db.executeUpdate(sql,nil)
【深度解析:iOS平台下的数据库技术与应用】相关文章:
用户评论
想学习iOS开发,了解一下数据管理体系好像挺重要啊!
有13位网友表示赞同!
以前用安卓做APP的时候就经常用SQLite了,iOS也是一样吗?
有15位网友表示赞同!
iOS自带的数据库存储方案有哪些?有人推荐一下吗?
有7位网友表示赞同!
对于一款大型的 iOS 应用,数据库的选择非常关键吧。
有15位网友表示赞同!
学习一些iOS数据库知识能增强Android开发能力吗?
有5位网友表示赞同!
想了解下常见的iOS数据库框架有哪些特性区别
有19位网友表示赞同!
数据库设计原则和iOS系统的配合有什么讲究吗?
有11位网友表示赞同!
iOS应用程序性能优化中,数据库管理会起到什么作用?
有11位网友表示赞同!
学习iOS数据库感觉需要一些SQL基础知识吧!
有8位网友表示赞同!
想了解一下ios数据库的安全性,如何保护数据隐私呢?
有8位网友表示赞同!
有没有适合小规模项目使用的高效轻量级的 iOS 数据库工具?
有18位网友表示赞同!
iOS数据库的并发访问控制机制怎么实现效率比较高呢?
有13位网友表示赞同!
iOS开发者在实际开发中运用数据库碰到什么难点?
有7位网友表示赞同!
ios应用程序如何使用数据库进行实时数据同步?
有5位网友表示赞同!
想了解一下iOS数据库和本地缓存技术的结合方式!
有11位网友表示赞同!
有没有好玩的iOS数据库交互工具,可以方便地管理数据?
有16位网友表示赞同!
iOS数据库如何与云端服务器进行数据整合?
有17位网友表示赞同!
学习完iOS数据库之后,可以开发什么样类型的应用程序呢?
有17位网友表示赞同!
对iOS数据库技术有深入了解的人能分享一些实际案例吗?
有9位网友表示赞同!