IOS多线程读写Sqlite问题解决

现在ios里使用的数据库一般都是Sqlite,但是使用Sqlite有个不太好的地方就是在多线程的时候,会出现问题,sqlite只能打开一个读或者写连结。这样的话多线程就会碰到资源占用的问题。

 

最开始是使用FMDB,FMDB的早期版本不能解决这个问题,后来FMDB更新了,新版本的FMDB能够很好的解决这个多线程使用Sqlite 。

FMDB github网址  https://github.com/ccgus/fmdb 最新版的请到github取下载。

 

本文演示了使用FMDB通过多线程来读和写数据库操作。

1.建立数据库表,我采用的是Firefox的Sqlite manager 来建立的。

  建表sql如下

 CREATE TABLE "tbl_user" ("_id" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL , "name" VARCHAR(30), "password" VARCHAR(30))

 

 2. 建立数据表的映射实体UserEntity

#import <Foundation/Foundation.h>

@interface UserEntity : NSObject
{
     int _id;
    NSString *name;
    NSString *password;
}

@property (nonatomic, assign) int ID;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *password;

@end 

 

3. 建立操作数据库的dao

//
//   DbDao.m
//   SqliteTest
//
//   Created by foxwang on 12-4-9.
//   Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import  " DbDao.h "
#import  " DbFileManager.h "

#import  " FMDatabase.h "
#import  " FMDatabaseAdditions.h "
#import  " FMDatabasePool.h "
#import  " FMDatabaseQueue.h "
#import  " UserEntity.h "

static DbDao *gSharedInstance = nil;

@implementation DbDao
@synthesize dbFile;
@synthesize dbQueue;

+(DbDao *)sharedInstance
{
    @synchronized(self)
    {
         if (gSharedInstance == nil)
            gSharedInstance = [[DbDao alloc] init];
    }
     return gSharedInstance;    
}

- ( void)dealloc
{
    [self.dbFile release];
    self.dbQueue = nil;
    [super dealloc];
}

- ( id)init
{
    
    self = [super init];
     if (self)
    {
        self.dbFile = [DbFileManager dbFilePath];
        self.dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.dbFile];
        
        
    }
     return  self;
}


- (UserEntity *)rsToUser:(FMResultSet*)rs
{
    UserEntity *user = [[[UserEntity alloc] init] autorelease];
    user.ID = [rs intForColumn: @" _id "];
    user.name = [rs stringForColumn: @" name "];
    user.password = [rs  stringForColumn: @" password "];
     return user;
}

- ( void)addUser:(UserEntity *)user
{
    [self.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        [db open];
        NSString *sql =  @" insert into tbl_user(name, password) values (?, ?) ";
        [db executeUpdate:sql,user.name, user.password];
        [db close];
    }];  
}

- (NSArray *)getUsers;
{
    __block NSMutableArray *users = [[[NSMutableArray alloc] init] autorelease];  
    [self.dbQueue inDatabase:^(FMDatabase *db)   {
        [db open];
        NSString *sql =  @" select * from tbl_user  ";
        FMResultSet *rs = [db executeQuery:sql];
         while ([rs next])
        {
            [users addObject:[self rsToUser :rs]]; 
        }
        [db close];
    }];
     return users;
}

@end 

 

4. 编写测试方法

在didFinishLaunchingWithOptions 方法里启动3个线程 :2个线程写,1个线程读

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
     //  Override point for customization after application launch.
    self.viewController = [[[ViewController alloc] initWithNibName: @" ViewController " bundle:nil] autorelease];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    
    
    [NSThread detachNewThreadSelector:@selector(writeDbOne) toTarget:self withObject:nil];
    
    [NSThread detachNewThreadSelector:@selector(readDb) toTarget:self withObject:nil];
    
    [NSThread detachNewThreadSelector:@selector(writeDbTwo) toTarget:self withObject:nil];
    
     return YES;
}

 

- ( void)writeDbOne
{
    DbDao *dao = [DbDao  sharedInstance];
     for ( int i =  0; i <  500; i++)
    {
        @autoreleasepool 
        {
             UserEntity *user = [[[UserEntity alloc] init] autorelease];
             user.name = [NSString stringWithFormat: @" name %d ", i];
             user.password = [NSString stringWithFormat: @" password %d ", i];
             [dao addUser:user];
             NSLog( @" writeDbOne %d  ", i);
        }
       
    }
}

- ( void)writeDbTwo
{
    DbDao *dao = [DbDao  sharedInstance];
     for ( int i =  600; i <  1200; i++)
    {
        @autoreleasepool 
        {
            UserEntity *user = [[[UserEntity alloc] init] autorelease];
            user.name = [NSString stringWithFormat: @" name %d ", i];
            user.password = [NSString stringWithFormat: @" password %d ", i];
            [dao addUser:user];
            NSLog( @" writeDbTwo %d  ", i);
        }
        
    }
}

- ( void)readDb
{
     DbDao *dao = [DbDao  sharedInstance];
     NSArray *users =   [dao getUsers];
     NSLog( @" %@ ", users);

 

最后查看数据库信息,数据成功插入

 

 

 

结论 :使用新的FMDB ,很好的解决了多线程问题。 

 

 项目文件下载

 

团结就是力量,ios开发者自己的推广联盟 QQ群173063969  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python中使用多线程存储SQLite数据时,需要注意以下几点: 1. 每个线程应该拥有自己的数据库连接,以避免多个线程共享同一个连接导致的数据不一致问题。 2. 每个线程应该在自己的连接上执行数据库操作,而不是在其他线程的连接上执行。 3. 在执行写操作时,应该使用事务来保证数据的一致性和完整性。 下面是一个使用多线程存储SQLite数据的示例代码: ```python import sqlite3 import threading # 创建全局Thread Local Storage thread_local = threading.local() # 在每个线程中获取一个数据库连接 def get_db(): if not hasattr(thread_local, 'db'): thread_local.db = sqlite3.connect('mydatabase.db') return thread_local.db # 执行查询操作 def query(query, args=()): cur = get_db().cursor() cur.execute(query, args) results = cur.fetchall() cur.close() return results # 执行写操作 def execute(query, args=()): db = get_db() db.execute(query, args) db.commit() # 在写操作时使用事务 def execute_with_transaction(query, args=()): db = get_db() with db: db.execute(query, args) # 关闭连接 def close_db(): if hasattr(thread_local, 'db'): thread_local.db.close() del thread_local.db ``` 在使用上述代码时,可以在每个线程中调用`get_db()`函数获取一个数据库连接,然后在连接上执行查询或写操作。在执行写操作时,可以选择使用`execute()`函数来直接执行,或者使用`execute_with_transaction()`函数来执行带有事务的操作。 最后,在程序结束时应该调用`close_db()`函数来关闭所有连接。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值