多线程update mysql的问题_数据库多线程问题

本文介绍了多线程环境下数据库操作的问题,包括使用FMDatabaseQueue确保FMDB线程安全,理解事务的概念以及如何在CoreData中进行多线程操作,强调了线程间数据同步的重要性。
摘要由CSDN通过智能技术生成

1.FMDB线程安全的实现

应用中不可在多个线程中共同使用一个FMDatabase对象操作数据库,这样会引起数据库数据混乱。如果要实现多线程,就需要使用FMDatabaseQueue。FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithPath:[self getDatabasePath]];

用FMDatabaseQueue来创建队列,所有的操作都在block中执行。//插入数据

[queue inDatabase:^(FMDatabase *database) {

//写入数据

sql = @"insert into Test (name,image) values (?,?)";

[database executeUpdate:sql,@"张三",data];

}];

实现原理:在应用中只有一个FMDatabaseQueue实例,所有的任务都使用这一个共同的实例。FMDatabaseQueue其实是创建了一个gcd串行队列,放入队列中的block都串行执行,这就保证了同一时间队列中只执行一个操作,避免数据的混乱。

2.事务的概念

如果要保证多个操作同时成功或同时失败,可以把多个操作放到事务里。[queue inTransaction:^(FMDatabase *db,BOOL*rollback) {

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumbernumberWithInt:1]];

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumbernumberWithInt:2]];

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumbernumberWithInt:3]];

if(whoopsSomethingWrongHappened) { *rollback =YES;return;如果发生错误就进行回滚,把之前已经执行的任务都取消}// ...

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumbernumberWithInt:4]];}];

3.coredata多线程

1.初始化moc(托管对象上下文,NSManagedObjectContext)的时候可以指定并发队列。NSPrivateQueueConcurrencyType 私有并发队列类型,操作在子线程完成。

NSMainQueueConcurrencyType 主并发队列类型,涉及到UI相关操作应该使用这个队列。

2.调用方式,不能直接在不同的线程里使用同一个moc,会造成数据混乱:- (void)performBlock:(void(^)())block 异步执行的block,调用之后会立刻返回。

- (void)performBlockAndWait:(void(^)())block同步执行的block,调用之后会等待这个任务完成,才会继续向下执行。

比如说,在多线程的环境下执行MOC的save方法,就是将save方法放在MOC的block体中异步执行,其他方法的调用也是一样的。[context performBlock:^{

[context save:nil];异步执行save

}];⚠️:这种方法和我们之前做线程切换的方式是不一样的,不能自己开一个子线程然后到子线程里面去执行moc,应该是调用moc自身绑定的队列,把操作放到block里去执行。

iOS5之前使用多个moc:可能有多个MOC关联在同一个PSC上,当一个MOC发生改变并持久化到本地时,系统并不会将其他MOC缓存在内存中的NSManagedObject对象改变。所以这就需要我们在MOC发生改变时,将其他MOC数据更新。

多个moc关联同一个psc,在通知中心注册NSNotification。// 创建主队列MOC,用于执行UI操作NSManagedObjectContext*mainMOC = [[NSManagedObjectContextalloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; mainMOC.persistentStoreCoordinator = PSC;

// 创建私有队列MOC,用于执行其他耗时操作NSManagedObjectContext*backgroundMOC = [[NSManagedObjectContextalloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; backgroundMOC.persistentStoreCoordinator = PSC;

// 通过监听NSManagedObjectContextDidSaveNotification通知,来获取所有MOC的改变消息

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:nil];

// MOC改变后的通知回调

- (void)contextChanged:(NSNotification *)noti {

NSManagedObjectContext *MOC = noti.object;

[MOC performBlock:^{

// 直接调用系统提供的同步API,系统内部会完成同步的实现细节。

[MOC mergeChangesFromContextDidSaveNotification:noti];

}];}

iOS5之前的数据同步:

简单数据冲突,一个moc数据发生改变,提交存储区,其他moc并没有对这个改变的数据进行更新。

有三种通知方式:NSManagedObjectContextWillSaveNotification

NSManagedObjectContextDidSaveNotification

NSManagedObjectContextObjectsDidChangeNotification

监听到通知以后调用同步api,mergeChangesFromContextDidSaveNotification:noti

复杂数据同步:一个moc对本地数据的存储做出了改变,另一个moc也对相同的数据存储做了改变,这样在save的时候就产生了数据冲突。

这种情况下可以设置moc的mergePolicy属性来指定解决冲突的具体方案。一共有五种属性值。NSErrorMergePolicy: 默认值,当出现合并冲突时,返回一个NSError对象来描述错误,而MOC和持久化存储区不发生改变。

NSMergeByPropertyStoreTrumpMergePolicy:  以本地存储为准,使用本地存储来覆盖冲突部分。

NSMergeByPropertyObjectTrumpMergePolicy:  以MOC的为准,使用MOC来覆盖本地存储的冲突部分。

NSOverwriteMergePolicy:  以MOC为准,用MOC的所有NSManagedObject对象覆盖本地存储的对应对象。

NSRollbackMergePolicy:    以本地存储为准,MOC所有的NSManagedObject对象被本地存储的对应对象所覆盖。

iOS5之后使用多个moc:

关联了PSC的MOC是parentMOC,parentMOC执行save操作时真正将数据写入了本地数据库。每一个parentMOC都可以有多个childMOC,但是childMOC并不会关联parentMOC,childMOC执行save操作的时候并不会真正把数据写入数据库,而是会通知他的parentMOC自己发生了改变,由parentMOC完成写入数据库的任务。// 创建PSC实例对象,还是用上面Demo的实例化代码

NSPersistentStoreCoordinator *PSC = self.persistentStoreCoordinator;

// 创建主队列MOC,用于执行UI操作

NSManagedObjectContext *mainMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

mainMOC.persistentStoreCoordinator = PSC;

// 创建私有队列MOC,用于执行其他耗时操作,backgroundMOC并不需要设置PSC

NSManagedObjectContext *backgroundMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

backgroundMOC.parentContext = mainMOC;

[backgroundMOC performBlock:^{

[backgroundMOC save:nil];

[mainMOC performBlock:^{

[mainMOC save:nil];//私有队列调用了save方法之后,主队列也要调用save方法,这样才能实现本地数据持久化。

}];

}];

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值