SQL基本操作
1.create 和 drop
-
create table 表名 (字段名1 字段类型1, 字段名2 字段类型2, …) ;
-
create table t_student (id integer, name text, age integer, score real) ;
-
create table if not exists 表名 (字段名1 字段类型1, 字段名2 字段类型2, …) ;
2.增、改、删
insert
-
insert into 表名 (字段1, 字段2, …) values (字段1的值, 字段2的值, …) ;
-
insert into t_student (name, age) values (‘mj’, 10) ;
update
-
update 表名 set 字段1 = 字段1的值, 字段2 = 字段2的值, … ;
-
update t_student set name = ‘jack’, age = 20 ;
delete
-
delete from 表名 ;
-
delete from t_student ;
数据类型
SQLite将数据划分为以下几种存储类型:
-
integer : 整型值
-
real : 浮点值
-
text : 文本字符串
-
blob : 二进制数据(比如文件)
-
SQLite是无类型的,就算声明为integer类型,还是能存储字符串文本(主键除外)。
建表时声明啥类型或者不声明类型都可以,也就意味着创表语句可以这么写:create table t_student(name, age);
-
数据库中的字符串内容应该用单引号 ’ 括住
条件语句
where
-
where 字段 = 某个值 ; // 不能用两个 =
-
where 字段 is 某个值 ; // is 相当于 =
-
where 字段 != 某个值 ;
-
where 字段 is not 某个值 ; // is not 相当于 !=
-
where 字段 > 某个值 ;
-
where 字段1 = 某个值 and 字段2 > 某个值 ; // and相当于C语言中的 &&
-
where 字段1 = 某个值 or 字段2 = 某个值 ; // or 相当于C语言中的 ||
例子:
(1)将t_student表中年龄大于10 并且 姓名不等于jack的记录,年龄都改为 5
update t_student set age = 5 where age > 10 and name != ‘jack’ ;
(2)删除t_student表中年龄小于等于10 或者 年龄大于30的记录
delete from t_student where age <= 10 or age > 30 ;
(3)将t_student表中名字等于jack的记录,score字段的值 都改为 age字段的
update t_student set score = age where name = ‘jack’ ;
select
-
select 字段1, 字段2, … from 表名 ;
select name, age from t_student ; select * from t_student where age > 10 ; // 条件查询
-
select 字段1 别名 , 字段2 别名 , … from 表名 别名 ;
select name myname, age myage from t_student s; select s.myname, s.myage from t_student s ;
-
计算记录的数量
select count (字段) from 表名 ;
select count (age) from t_student ;
select count ( * ) from 表名 ;
select count ( * ) from t_student where score >= 60;
-
排序
select * from t_student order by 字段 ;
select * from t_student order by age ; select * from t_student order by age desc ; //降序 select * from t_student order by age asc ; // 升序(默认)
先按照年龄排序(升序),年龄相等就按照身高排序(降序)
select * from t_student order by age asc, height desc ;
limit(精准查询)
-
select * from 表名 limit 数值1, 数值2 ;
select * from t_student limit 4, 8 ;//跳过最前面4条语句,然后取8条记录 select * from t_student limit 7 ;//这条语句的作用相当于select * from t_student limit 0, 7 ;表示取最前面的7条记录
-
limit常用来做分页查询,比如每页固定显示5条数据,那么应该这样取数据
第1页:limit 0, 5
第2页:limit 5, 5
第3页:limit 10, 5
第n页:limit 5*(n-1), 5
约束
简单约束
-
not null :规定字段的值不能为null
-
unique :规定字段的值必须唯一
-
default :指定字段的默认值
create table t_student (id integer, name text not null unique, age integer not null default 1) ;//name字段不能为null,并且唯一;age字段不能为null,并且默认为1
主键约束
-
主键:每张表里都需要有一个字段,来保证数据的唯一性;
-
主键可以是一个字段或多个字段;
-
主键应当是对用户没有意义的
-
永远也不要更新主键
-
主键不应包含动态变化的数据
-
主键应当由计算机自动生成
-
声明主键
create table t_student (id integer primary key autoincrement, name text, age integer) ;//primary key,就说明是一个主键字段;如果想要让主键自动增长(必须是integer类型),应该增加autoincrement
外键约束
-
外键:一张表的某个字段,引用着另一张表的主键字段,用来建立表与表之间的联系。
create table t_student (id integer primary key autoincrement, name text, age integer, class_id integer, constraint fk_student_class foreign key (class_id) references t_class (id));//t_student表中有一个叫做fk_t_student_class的外键; 这个外键的作用是用t_student表中的class_id字段引用t_class表的id字段
表连接查询
-
表连接:需要联合多张表才能查询到数据。
-
内连接:inner join 或者 join (显示的是左右表都有完整字段值的记录)
-
左外连接:left outer join (保证左表数据的完整性)
select s.name,s.age from t_student s, t_class c where s.class_id = c.id and c.name = ‘0316iOS’;//查询0316iOS班的所有学生的姓名和年龄
FMDB
主要的类
-
FMDatabase – 表示一个单独的SQLite数据库。 用来执行SQLite的命令;
-
FMResultSet – 表示FMDatabase执行查询后结果集;
-
FMDatabaseQueue – 如果你想在多线程中执行多个查询或更新,你应该使用该类。这是线程安全的;
创建数据库
FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
-
该文件路径无需真实存,如果不存在会自动创建;
-
空字符串(@”")。表示会在临时目录创建一个空的数据库,当FMDatabase 链接关闭时,文件也被删除;
-
NULL. 将创建一个内在数据库。同样的,当FMDatabase连接关闭时,数据会被销毁;
打开数据库
与数据库交互前,必须先打开数据库,如果资源或权限不足,将会打开失败。
if (![db open]) {
[db release];
return;
}
执行更新
一切不是select的命令都是更新命令。执行更新会返回一个BOOL值。YES表示执行成功,否则有错误。相关方法:
-
-lastErrorMessage
-
-lastErrorCode
使用executeUpdate:
执行更新
-(BOOL)executeUpdate:(NSString*)sql, ...
-(BOOL)executeUpdateWithFormat:(NSString*)format, ...
-(BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
示例:
[db executeUpdate:@"UPDATE t_student SET age = ? WHERE name = ?;", @20, @"Jack"]
[db executeUpdateWithFormat:@"INSERT INTO t_shop(name, price) VALUES (%@, %f);", shop.name, shop.price];
注意:参数必须是对象类型。比如要把int型变成NSNumber对象;
SQL中使用%要用%%;
执行查询
select命令,执行方法是以-excuteQuery
开头的。
-
成功返回FMResultSet对象, 错误返回nil;
-
支持使用
NSError**
参数 -
-lastErrorMessage
-
-lastErrorCode
使用executeQuery:
执行更新
-(FMResultSet *)executeQuery:(NSString*)sql, ...
-(FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
-(FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
示例:
// 查询数据
FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student"];
// 遍历结果集
while ([rs next]) {
NSString *name = [rs stringForColumn:@"name"];
int age = [rs intForColumn:@"age"];
double score = [rs doubleForColumn:@"score"];
}
类型转换
参数是查询结果集的列的索引位置
- intForColumn:
- longForColumn:
- longLongIntForColumn:
- boolForColumn:
- doubleForColumn:
- stringForColumn:
- dataForColumn:
- dataNoCopyForColumn:
- UTF8StringForColumnIndex:
- objectForColumn:
你无需调用 [FMResultSet close]来关闭结果集, 当新的结果集产生,或者其数据库关闭时,会自动关闭。
关闭数据库
使用完数据库后,关闭数据库连接来释放SQLite资源。
[db close]
事务和多线程
事务:是执行多个SQL语句时,如果有一个失败了,则回滚到原始状态。主要用来确保所有的SQL逻辑必须完成。
多线程:如果多个线程同时访问FMDatabase实例,会造成混乱,所以要用FMDatabaseQueue:
- FMDatabaseQueue的创建
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
- 简单使用
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"];
FMResultSet *rs = [db executeQuery:@"select * from t_student"];
while ([rs next]) {
// …
}
}];
- 轻松地把简单任务包装到事务里
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"];
FMResultSet *rs = [db executeQuery:@"select * from t_student"];
while ([rs next]) {
// …
}
}];
事务回滚
*rollback = YES;
NSUserDefault
NSUserDefault:是一个单例,在整个程序中,只有一个实例对象,可以用于数据的永久保存,且简单实用,这是他可以让数据自由传递的一个前提(可以存储用户信息,夜间模式,字体大小)
其实存储后也是一个plist文件。
存储基本数据类型
-
NSNumber(NSInteger,float,double)
-
NSString,NSArray,NSDictionary,BOOL
示例:
//使用NSUserDefault进行存储
//1:创建要存储的数组
NSArray *array = @[@"11", @"22",@"33"];
//创建NSUserDefault对象
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:array forKey:@"userArray"];
NSLog(@"%@",user);
//读取
NSArray *newarr = [user objectForKey:@"userArray"];
NSLog(@"%@",newarr);
存储的对象必须是不可变,如果要存储可变的数组和字典,应该先转换成不可变的之后再存储。
存储自定义对象
- 对象要遵守NSCoding协议、copy协议,进行归档、解档
//归档
-(void)encodeWithCoder:(NSCoder *)aCoder{
unsigned int count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i < count; i++) {
const char * propertyCsString = property_getName(properties[i]);
NSString * propertyName = [NSString stringWithCString:propertyCsString encoding:NSUTF8StringEncoding];
id propertyValue = [self valueForKey:propertyName];
[aCoder encodeObject:propertyValue forKey:propertyName];
}
free(properties);
}
//解档
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
unsigned int count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i < count; i++) {
const char *property_csNam = property_getName(properties[i]);
NSString *p_key = [NSString stringWithCString:property_csNam encoding:NSUTF8StringEncoding];
id value = [aDecoder decodeObjectForKey:p_key];
[self setValue:value forKey:p_key];
}
free(properties);
}
return self
}
///copy 协议
-(id)copyWithZone:(NSZone *)zone{
StudentModel *s_model = [[self copyWithZone:zone] init];
unsigned int count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i < count; i++) {
const char *propertyCS = property_getName(properties[i]);
NSString *p_key = [NSString stringWithCString:propertyCS encoding:NSUTF8StringEncoding];
id p_value = [self valueForKey:p_key];
[s_model setValue:p_value forKey:p_key];
}
free(properties);
return s_model;
}
- 转换成NSData再进行存储
StudentModel *s_model = [[StudentModel alloc] init];
s_model.s_name = @"xiaoqiang";
s_model.s_id = @"22";
s_model.s_password = @"123456";
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:s_model];
[u_default setObject:data forKey:@"s_student"];
[u_default synchronize];
NSData *rachiverData = [u_default objectForKey:@"s_student"];
StudentModel *model = [NSKeyedUnarchiver unarchiveObjectWithData:rachiverData];
NSLog(@"\n name is %@ \n id is %@ \n password is %@",model.s_name,model.s_id,model.s_password);
调用 synchronize 立刻同步数据到文件内,不然会有延迟。
[mySettingData synchronize];
删除对应的key
- (void)removeObjectForKey:(NSString *)defaultName;
//或者
[[NSUserDefaults ] setObject:nil]
Plist
主要用来存储大文件。
缺点:需要将所有的数据取出再全部保存。
存储基本数据类型(array,dictionary,string,bool,date,data)
- 存入字典和数组
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict writeToFile:@"filePath" atomically:YES];
NSMutableArray *array = [NSMutableArray array];
[array writeToFile:@"filePath" atomically:YES];
- 读取数组和字典
//方法1:
NSString *filePath=[[NSBundle mainBundle] pathForResource:@"myDict" ofType:@"plist"];
NSDictionary *myDic = [[NSDictionary alloc]initWithContentsOfFile:filePath];
NSString *filePath=[[NSBundle mainBundle] pathForResource:@"myArr" ofType:@"plist"];
NSArray *myArr2 = [[NSArray alloc] initWithContentsOfFile:filePath];
//方法2:
NSString *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *filePath = [docPath stringByAppendingPathComponent: @"myData.plist"];
NSDictionary *infoDic = [NSDictionary dictionaryWithContentsOfFile: filePath];
存储自定义数据类型
- 也要实现归档协议然后转换成NSData类型储存
NSString *path = [self getPlistLibraryWithSuffix:@"test.plist"];
NSMutableArray *stu_array = [NSMutableArray new];
for (int i = 0; i < 10; i ++) {
StudentModel *s_model = [StudentModel new];
s_model.s_name = [NSString stringWithFormat:@"name%d",i];
s_model.s_id = [NSString stringWithFormat:@"%d",100 + i];
s_model.s_password = @"123456";
[stu_array addObject:s_model];
}
///写入
NSData *archiverData = [NSKeyedArchiver archivedDataWithRootObject:stu_array];
BOOL isSuc = [archiverData writeToFile:path atomically:YES];
// BOOL isSuc = [NSKeyedArchiver archiveRootObject:stu_array toFile:path];
NSLog(@"%d",isSuc);
///读取
NSData *unarchiverData = [NSData dataWithContentsOfFile:path];
NSArray *unArchiverArr = [NSKeyedUnarchiver unarchiveObjectWithData:unarchiverData];
// NSArray *unArchiverArr = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSLog(@"%@==",unArchiverArr);
删除plist文件
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager isExecutableFileAtPath:@"filePath"]) {
NSError *error;
[fileManager removeItemAtPath:@"filePath" error:&error];
}
沙盒
总结:
-
Document 保存用户生成的数据(会备份)
-
Library/Cache 保存服务器数据或日志(不会备份)
-
temp 保存临时数据、经常要删除的
相关操作
- 获取路径
//Document
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
//library
NSString *libraryPath = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0];
//cache
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
//temp
NSString *tempPath = NSTemporaryDirectory();
- 创建目录、创建文件
//document path
NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
//test path
NSString *testPath= [documentsPath stringByAppendingPathComponent:@"test"];
//file path
NSString *filePath = [testPath stringByAppendingString:@"file.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
// 创建目录
[fileManager createDirectoryAtPath:testPath withIntermediateDirectories:YES attributes:nil error:nil];
// 创建文件
[fileManager createFileAtPath:filePath contents:nil attributes:nil];
- 获取目录下的所有文件名
NSArray *fileNameArrray = [fileManager subpathsOfDirectoryAtPath:documentsPath error:nil];
//可能目录比较深,耗性能
NSArray *fileNameArrray = [fileManager subpathsAtPath:documentsPath];
- 更改到当前目录操作
//之后都在document文件夹中操作
[fileManager changeCurrentDirectoryPath:documentsPath];
- 删除目录、删除文件(将其移动到temp目录)
//删除目录
[fileManager removeItemAtPath:documentsPath error:nil];
//删除文件
[fileManager removeItemAtPath:filePath error:nil];
- 写入数据
NSString *temp = @"nihao 世界";
int dataInt = 1234;
float dataFloat = 3.14f;
//创建数据缓冲
NSMutableData *writer = [[NSMutableData alloc] init];
//将字符串添加到缓冲中
[writer appendData:[temp dataUsingEncoding:NSUTF8StringEncoding]];
//将其他数据添加到缓冲中
[writer appendBytes:&dataInt length:sizeof(dataInt)];
[writer appendBytes:&dataFloat length:sizeof(dataFloat)];
//将缓冲的数据写入到文件中
[writer writeToFile:path atomically:YES];
- 读取数据
int intData;
float floatData = 0.0;
NSString *stringData;
NSData *reader = [NSData dataWithContentsOfFile:path];
stringData = [[NSString alloc] initWithData:[reader subdataWithRange:NSMakeRange(0, [temp length])]
encoding:NSUTF8StringEncoding];
[reader getBytes:&intData range:NSMakeRange([temp length], sizeof(intData))];
[reader getBytes:&floatData range:NSMakeRange([temp length] + sizeof(intData), sizeof(floatData))];
NSLog(@"stringData:%@ intData:%d floatData:%f", stringData, intData, floatData);
网友评论