iOS开发中SQLite死锁问题(OC版)
翻自己的博客发现自己以前写过如何使用SQLite,然后当时好像没提死锁的事情。因为SQLite只支持单线程的,所以如果碰到多个功能需要访问SQLite的,很有可能引起死锁问题。当然了,现在可能都用Swift不用OC了,但是为了方案的完整性,我还是要记录一下这件事情。
那么比较常见的就是@synchronized关键字,这个Java的同学应该很熟悉,过多的解释也没什么好说的,前人都已经栽树成林了,我没必要再多啰嗦了。
以下是两年前的代码了,也是为了补之前那篇博客《iOS SQLite3 “增删改查”(Objective-C)》的坑
代码或者博客写的不好,还请多多指教,感谢!
//
// SQLite.h
//
// Created by Zhan on 16/9/8.
// Copyright © 2016年 Michael Zhan. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <sqlite3.h>
typedef void (^SelectBlock)(NSMutableArray * mutableArray);
typedef void (^DBFailureBlock)(void);
typedef void (^Success)(void);
typedef void (^Failed)(void);
@interface ContactDB : NSObject
+ (ContactDB *)sharedDataBaseHandle;
-(sqlite3 *)openDB;
-(void)createTable;
-(void)dropTable:(Success)successBlock failed:(Failed)failedBlock;
-(void)insert_name:(NSString *)name phone:(NSString *)phone headimg:(NSString *)path deptId:(NSString *)deptId deptName:(NSString *)deptName uppercase:(NSString *)uppercase userId:(NSString *)userId mail:(NSString *)mail;
-(void)loadContact:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock;
-(void)select_name:(NSString *)name success:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock;
-(void)select_phone:(NSString *)phone success:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock;
-(void)select_uppercase:(NSString *)uppercase success:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock;
-(void)select_userId:(NSString *)userId success:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock;
-(void)select_deptName:(NSString *)deptName success:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock;
-(void)closeDB;
+ (void)destroyDealloc;
@end
//
// SQLite.m
//
// Created by Zhan on 16/9/8.
// Copyright © 2016年 Michael Zhan. All rights reserved.
//
#import "ContactDB.h"
@implementation ContactDB
static ContactDB *manager = nil;
static sqlite3 * db = nil; //设置句柄 通过句柄对数据库进行操作
static bool isOperation;
+(ContactDB *)sharedDataBaseHandle{
if (manager == nil) {
manager = [[ContactDB alloc] init];
isOperation = false;
}
return manager;
}
-(sqlite3 *)openDB{
if (db != nil) {
return db;
}
NSArray *test = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString * fileName = [[test lastObject]stringByAppendingPathComponent:@"Contact"];
NSLog(@"%@",fileName); //打印路径
sqlite3_open(fileName.UTF8String, &db);
[self dropTable:^{
[self createTable];
} failed:^{
}];
return db;
}
-(void)createTable{
NSString * sql = [[@"create table if not exists "stringByAppendingString:@"Contact"]stringByAppendingString:@" (id integer primary key autoincrement not null, name text not null, phone text not null, headimg text null, deptId text not null, deptName text not null, uppercase text null, userId text not null, mail text null);"];
// NSLog(@"sql : %@",sql);
if(db == nil){
return;
}
sqlite3_exec(db, sql.UTF8String, NULL, NULL, NULL);
// NSLog(@"create contact error : %s",err);
}
-(void)loadContact:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock{
sqlite3_stmt *statement = nil;
NSString *sql = @"select * from Contact";
// NSLog(@"sql == %@",sql);
// BOOL hasRow = false;
if(db == nil && isOperation == true){
return;
}
NSMutableArray * mutableArray = [[NSMutableArray alloc]init];
isOperation = true;
@synchronized(self){
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
// hasRow = true;
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc]init];
char *name = (char *)sqlite3_column_text(statement, 1);
NSString *nameStr = [[NSString alloc] initWithUTF8String:name];
[mutableDictionary setObject:nameStr forKey:@"name"];
char *phone = (char *)sqlite3_column_text(statement, 2);
NSString *phoneStr = [[NSString alloc]initWithUTF8String:phone];
[mutableDictionary setObject:phoneStr forKey:@"phone"];
char *headimg = (char *)sqlite3_column_text(statement, 3);
NSString *headimgStr = [[NSString alloc]initWithUTF8String:headimg];
[mutableDictionary setObject:headimgStr forKey:@"headimg"];
char *deptId = (char *)sqlite3_column_text(statement, 4);
NSString *deptIdStr = [[NSString alloc]initWithUTF8String:deptId];
[mutableDictionary setObject:deptIdStr forKey:@"deptId"];
char *deptName = (char *)sqlite3_column_text(statement, 5);
NSString *deptNameStr = [[NSString alloc]initWithUTF8String:deptName];
[mutableDictionary setObject:deptNameStr forKey:@"deptName"];
char *uppercase = (char *)sqlite3_column_text(statement, 6);
NSString *uppercasetStr = [[NSString alloc]initWithUTF8String:uppercase];
[mutableDictionary setObject:uppercasetStr forKey:@"uppercase"];
char *userId = (char *)sqlite3_column_text(statement, 7);
NSString *userIdStr = [[NSString alloc]initWithUTF8String:userId];
[mutableDictionary setObject:userIdStr forKey:@"userId"];
char *mail = (char *)sqlite3_column_text(statement, 8);
NSString *mailStr = [[NSString alloc]initWithUTF8String:mail];
[mutableDictionary setObject:mailStr forKey:@"mail"];
[mutableArray addObject:mutableDictionary];
}
isOperation = false;
successBlock(mutableArray);
}else{
failureBlock();
}
sqlite3_finalize(statement);
}
}
- (void)insert_name:(NSString *)name phone:(NSString *)phone headimg:(NSString *)path deptId:(NSString *)deptId deptName:(NSString *)deptName uppercase:(NSString *)uppercase userId:(NSString *)userId mail:(NSString *)mail{
BOOL hasInfo = false;
sqlite3_stmt *statement = nil;
NSString *select = [[@"select * from Contact where userId = '"stringByAppendingString:userId]stringByAppendingString:@"'"];
@synchronized (self) {
if(db == nil && isOperation == true){
return;
}
isOperation = true;
if (sqlite3_prepare_v2(db, [select UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
hasInfo = true;
break;
}
}
uppercase = [uppercase stringByReplacingOccurrencesOfString:@" " withString:@""];
NSString * sql;
if(hasInfo){
sql = [NSString stringWithFormat:@"update Contact set name = '%@', phone = '%@', headimg = '%@', deptId = '%@', deptName = '%@', uppercase = '%@', mail = '%@' where userId = '%@'",name, phone, path, deptId, deptName, uppercase, mail, userId];
}else{
sql = [NSString stringWithFormat:@"insert into Contact (name, phone, headimg, deptId, deptName, uppercase, userId, mail) VALUES('%@', '%@', '%@', '%@', '%@', '%@', '%@', '%@')", name, phone, path, deptId, deptName, uppercase, userId, mail];
}
sqlite3_exec(db, sql.UTF8String, NULL, NULL, NULL);
isOperation = false;
sqlite3_finalize(statement);
}
-(void)select_name:(NSString *)name success:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock{
sqlite3_stmt *statement = nil;
NSString *sql = [[@"select * from Contact where name LIKE '%"stringByAppendingString:name]stringByAppendingString:@"%'"];
NSMutableArray * mutableArray = [[NSMutableArray alloc]init];
if(db == nil && isOperation == true){
return;
}
isOperation = true;
@synchronized (self) {
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc]init];
char *name = (char *)sqlite3_column_text(statement, 1);
NSString *nameStr = [[NSString alloc] initWithUTF8String:name];
[mutableDictionary setObject:nameStr forKey:@"name"];
char *phone = (char *)sqlite3_column_text(statement, 2);
NSString *phoneStr = [[NSString alloc]initWithUTF8String:phone];
[mutableDictionary setObject:phoneStr forKey:@"phone"];
char *headimg = (char *)sqlite3_column_text(statement, 3);
NSString *headimgStr = [[NSString alloc]initWithUTF8String:headimg];
[mutableDictionary setObject:headimgStr forKey:@"headimg"];
char *deptId = (char *)sqlite3_column_text(statement, 4);
NSString *deptIdStr = [[NSString alloc]initWithUTF8String:deptId];
[mutableDictionary setObject:deptIdStr forKey:@"deptId"];
char *deptName = (char *)sqlite3_column_text(statement, 5);
NSString *deptNameStr = [[NSString alloc]initWithUTF8String:deptName];
[mutableDictionary setObject:deptNameStr forKey:@"deptName"];
char *uppercase = (char *)sqlite3_column_text(statement, 6);
NSString *uppercasetStr = [[NSString alloc]initWithUTF8String:uppercase];
[mutableDictionary setObject:uppercasetStr forKey:@"uppercase"];
char *userId = (char *)sqlite3_column_text(statement, 7);
NSString *userIdStr = [[NSString alloc]initWithUTF8String:userId];
[mutableDictionary setObject:userIdStr forKey:@"userId"];
char *mail = (char *)sqlite3_column_text(statement, 8);
NSString *mailStr = [[NSString alloc]initWithUTF8String:mail];
[mutableDictionary setObject:mailStr forKey:@"mail"];
[mutableArray addObject:mutableDictionary];
}
isOperation = false;
successBlock(mutableArray);
}else{
failureBlock();
}
sqlite3_finalize(statement);
}
}
-(void)select_phone:(NSString *)phone success:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock{
sqlite3_stmt *statement = nil;
NSString *sql = [[@"select * from Contact where phone LIKE '%"stringByAppendingString:phone]stringByAppendingString:@"%'"];
// NSLog(@"sql == %@",sql);
NSMutableArray * mutableArray = [[NSMutableArray alloc]init];
if(db == nil && isOperation == true){
return;
}
isOperation = true;
@synchronized (self) {
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc]init];
char *name = (char *)sqlite3_column_text(statement, 1);
NSString *nameStr = [[NSString alloc] initWithUTF8String:name];
[mutableDictionary setObject:nameStr forKey:@"name"];
char *phone = (char *)sqlite3_column_text(statement, 2);
NSString *phoneStr = [[NSString alloc]initWithUTF8String:phone];
[mutableDictionary setObject:phoneStr forKey:@"phone"];
char *headimg = (char *)sqlite3_column_text(statement, 3);
NSString *headimgStr = [[NSString alloc]initWithUTF8String:headimg];
[mutableDictionary setObject:headimgStr forKey:@"headimg"];
char *deptId = (char *)sqlite3_column_text(statement, 4);
NSString *deptIdStr = [[NSString alloc]initWithUTF8String:deptId];
[mutableDictionary setObject:deptIdStr forKey:@"deptId"];
char *deptName = (char *)sqlite3_column_text(statement, 5);
NSString *deptNameStr = [[NSString alloc]initWithUTF8String:deptName];
[mutableDictionary setObject:deptNameStr forKey:@"deptName"];
char *uppercase = (char *)sqlite3_column_text(statement, 6);
NSString *uppercasetStr = [[NSString alloc]initWithUTF8String:uppercase];
[mutableDictionary setObject:uppercasetStr forKey:@"uppercase"];
char *userId = (char *)sqlite3_column_text(statement, 7);
NSString *userIdStr = [[NSString alloc]initWithUTF8String:userId];
[mutableDictionary setObject:userIdStr forKey:@"userId"];
char *mail = (char *)sqlite3_column_text(statement, 8);
NSString *mailStr = [[NSString alloc]initWithUTF8String:mail];
[mutableDictionary setObject:mailStr forKey:@"mail"];
[mutableArray addObject:mutableDictionary];
}
isOperation = false;
successBlock(mutableArray);
}else{
failureBlock();
}
sqlite3_finalize(statement);
}
}
-(void)select_uppercase:(NSString *)uppercase success:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock{
uppercase = [uppercase uppercaseString];
uppercase = [uppercase stringByReplacingOccurrencesOfString:@" " withString:@""];
sqlite3_stmt *statement = nil;
NSString *sql = [[@"select * from Contact where uppercase LIKE '%"stringByAppendingString:uppercase]stringByAppendingString:@"%'"];
// NSLog(@"sql == %@",sql);
NSMutableArray * mutableArray = [[NSMutableArray alloc]init];
if(db == nil && isOperation == true){
return;
}
isOperation = true;
@synchronized (self) {
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc]init];
char *name = (char *)sqlite3_column_text(statement, 1);
NSString *nameStr = [[NSString alloc] initWithUTF8String:name];
[mutableDictionary setObject:nameStr forKey:@"name"];
char *phone = (char *)sqlite3_column_text(statement, 2);
NSString *phoneStr = [[NSString alloc]initWithUTF8String:phone];
[mutableDictionary setObject:phoneStr forKey:@"phone"];
char *headimg = (char *)sqlite3_column_text(statement, 3);
NSString *headimgStr = [[NSString alloc]initWithUTF8String:headimg];
[mutableDictionary setObject:headimgStr forKey:@"headimg"];
char *deptId = (char *)sqlite3_column_text(statement, 4);
NSString *deptIdStr = [[NSString alloc]initWithUTF8String:deptId];
[mutableDictionary setObject:deptIdStr forKey:@"deptId"];
char *deptName = (char *)sqlite3_column_text(statement, 5);
NSString *deptNameStr = [[NSString alloc]initWithUTF8String:deptName];
[mutableDictionary setObject:deptNameStr forKey:@"deptName"];
char *userId = (char *)sqlite3_column_text(statement, 7);
NSString *userIdStr = [[NSString alloc]initWithUTF8String:userId];
[mutableDictionary setObject:userIdStr forKey:@"userId"];
char *uppercase = (char *)sqlite3_column_text(statement, 6);
NSString *uppercasetStr = [[NSString alloc]initWithUTF8String:uppercase];
[mutableDictionary setObject:uppercasetStr forKey:@"uppercase"];
[mutableArray addObject:mutableDictionary];
}
isOperation = false;
successBlock(mutableArray);
}else{
failureBlock();
}
sqlite3_finalize(statement);
}
}
-(void)select_userId:(NSString *)userId success:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock{
sqlite3_stmt *statement = nil;
NSString *sql = [[@"select * from Contact where userId = '"stringByAppendingString:userId]stringByAppendingString:@"'"];
if(db == nil && isOperation == true){
return;
}
NSMutableArray * mutableArray = [[NSMutableArray alloc]init];
@synchronized (self) {
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc]init];
char *name = (char *)sqlite3_column_text(statement, 1);
NSString *nameStr = [[NSString alloc] initWithUTF8String:name];
[mutableDictionary setObject:nameStr forKey:@"name"];
char *phone = (char *)sqlite3_column_text(statement, 2);
NSString *phoneStr = [[NSString alloc]initWithUTF8String:phone];
[mutableDictionary setObject:phoneStr forKey:@"phone"];
char *headimg = (char *)sqlite3_column_text(statement, 3);
NSString *headimgStr = [[NSString alloc]initWithUTF8String:headimg];
[mutableDictionary setObject:headimgStr forKey:@"headimg"];
char *deptId = (char *)sqlite3_column_text(statement, 4);
NSString *deptIdStr = [[NSString alloc]initWithUTF8String:deptId];
[mutableDictionary setObject:deptIdStr forKey:@"deptId"];
char *deptName = (char *)sqlite3_column_text(statement, 5);
NSString *deptNameStr = [[NSString alloc]initWithUTF8String:deptName];
[mutableDictionary setObject:deptNameStr forKey:@"deptName"];
char *uppercase = (char *)sqlite3_column_text(statement, 6);
NSString *uppercasetStr = [[NSString alloc]initWithUTF8String:uppercase];
[mutableDictionary setObject:uppercasetStr forKey:@"uppercase"];
char *userId = (char *)sqlite3_column_text(statement, 7);
NSString *userIdStr = [[NSString alloc]initWithUTF8String:userId];
[mutableDictionary setObject:userIdStr forKey:@"userId"];
char *mail = (char *)sqlite3_column_text(statement, 8);
NSString *mailStr = [[NSString alloc]initWithUTF8String:mail];
[mutableDictionary setObject:mailStr forKey:@"mail"];
[mutableArray addObject:mutableDictionary];
}
isOperation = false;
successBlock(mutableArray);
}else{
failureBlock();
}
sqlite3_finalize(statement);
}
}
-(void)select_deptName:(NSString *)deptName success:(SelectBlock)successBlock failure:(DBFailureBlock)failureBlock{
sqlite3_stmt *statement = nil;
NSString *sql = [[@"select * from Contact where deptName = '"stringByAppendingString:deptName]stringByAppendingString:@"'"];
// NSLog(@"sql == %@",sql);
if(db == nil && isOperation == true){
return;
}
NSMutableArray * mutableArray = [[NSMutableArray alloc]init];
@synchronized (self) {
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc]init];
char *name = (char *)sqlite3_column_text(statement, 1);
NSString *nameStr = [[NSString alloc] initWithUTF8String:name];
[mutableDictionary setObject:nameStr forKey:@"name"];
char *phone = (char *)sqlite3_column_text(statement, 2);
NSString *phoneStr = [[NSString alloc]initWithUTF8String:phone];
[mutableDictionary setObject:phoneStr forKey:@"phone"];
char *headimg = (char *)sqlite3_column_text(statement, 3);
NSString *headimgStr = [[NSString alloc]initWithUTF8String:headimg];
[mutableDictionary setObject:headimgStr forKey:@"headimg"];
char *deptId = (char *)sqlite3_column_text(statement, 4);
NSString *deptIdStr = [[NSString alloc]initWithUTF8String:deptId];
[mutableDictionary setObject:deptIdStr forKey:@"deptId"];
char *deptName = (char *)sqlite3_column_text(statement, 5);
NSString *deptNameStr = [[NSString alloc]initWithUTF8String:deptName];
[mutableDictionary setObject:deptNameStr forKey:@"deptName"];
char *uppercase = (char *)sqlite3_column_text(statement, 6);
NSString *uppercasetStr = [[NSString alloc]initWithUTF8String:uppercase];
[mutableDictionary setObject:uppercasetStr forKey:@"uppercase"];
char *userId = (char *)sqlite3_column_text(statement, 7);
NSString *userIdStr = [[NSString alloc]initWithUTF8String:userId];
[mutableDictionary setObject:userIdStr forKey:@"userId"];
char *mail = (char *)sqlite3_column_text(statement, 8);
NSString *mailStr = [[NSString alloc]initWithUTF8String:mail];
[mutableDictionary setObject:mailStr forKey:@"mail"];
[mutableArray addObject:mutableDictionary];
}
isOperation = false;
successBlock(mutableArray);
}else{
failureBlock();
}
sqlite3_finalize(statement);
}
}
-(void)dropTable:(Success)successBlock failed:(Failed)failedBlock{
NSString * sql = [@"drop table if exists "stringByAppendingString:@"Contact"];
NSLog(@"sql : %@",sql);
@synchronized (self) {
@try {
sqlite3_exec(db, sql.UTF8String, NULL, NULL, NULL);
successBlock();
} @catch (NSException *exception) {
failedBlock();
} @finally {
}
}
// sqlite3_exec(db, sql.UTF8String, NULL, NULL, NULL);
}
-(void)closeDB{
if (sqlite3_close(db) == SQLITE_OK){
db = nil;
}
}
+ (void)destroyDealloc{
if (nil == manager){
return;
}
manager = nil;
}
@end