GYDataCenter
GYDataContext, 데이터 의 추가 삭제, 수정 등 을 완료 합 니 다. 먼저 내부 개인 클래스 GYDataContextQueue 를 보십시오. 이것 은 FMDatabaseQueue 를 모방 하여 쓴 것 입 니 다. 직렬 대기 열 을 이용 하여 스 레 드 안전 을 보장 합 니 다.
@interface GYDataContextQueue : NSObject
@property (nonatomic, strong) NSMutableDictionary *cache;
@end
@implementation GYDataContextQueue {
dispatch_queue_t _queue;
}
static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey;
- (instancetype)initWithDBName:(NSString *)dbName {
self = [super init];
if (self) {
_queue = dispatch_queue_create([[NSString stringWithFormat:@"GYDataCenter.%@", dbName] UTF8String], NULL);
dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL);
_cache = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)dispatchSync:(dispatch_block_t)block {
GYDataContextQueue *currentQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey);
if (currentQueue == self) { // .....@1
block();
} else {
dispatch_sync(_queue, block);
}
}
@end
dispatch_queue_create 와 obbcsetAssociated Object 방법 은 유사 합 니 다. 대 의 는 대상 을 현재 대기 열 에 연결 하고 key 에 따라 꺼 내 는 것 입 니 다.dispatchSync 방법 에서 dispatchget_specific 는 현재 호출 대기 열 이 키 에 따라 연 결 된 값 을 가 져 오 는 것 입 니 다. @1 의 역할 은 현재 대기 열 에서 dispatch 를 다시 실행 하지 않도록 하 는 것 입 니 다.sync ( queue, block) 방법 으로 잠 금 을 방지 합 니 다.FMDB 에서
Get the currently executing queue (which should probably be nil, but in theory could be another DB queue
* and then check it against self to make sure we're not about to deadlock.
GYDataContext 의 4 대 기초 작업 을 살 펴 보 겠 습 니 다.
1. 조회 조작
- (id)getObject:(Class)modelClass properties:(NSArray*)properties
primaryKey:(id)primaryKey {
GYDataContextQueue *queue = [self queueForDBName:[modelClass dbName]];
__block id object = nil;
[queue dispatchSync:^{
NSMutableDictionary *cache = [self tableCacheFromDBCache:queue.cache class:modelClass];
object = [cache objectForKey:primaryKey];
if (!object || ((id)object).isFault) {
NSString *where = [self whereIdSqlForClass:modelClass];
NSArray *objects = [_dbRunner objectsOfClass:modelClass
properties:properties
where:where
arguments:@[ primaryKey ]];
object = [objects firstObject];
if (object && !properties.count) {
[cache setObject:object forKey:primaryKey];
}
}
}];
return object;
}
동기 화 대기 열 에서 메모리 캐 시 를 먼저 조회 하고 없 으 면 디스크 에서dbRunner 에서 찾 았 습 니 다. 메모리 캐 시 를 찾 았 습 니 다.
2. 쓰기 동작
- (void)saveObject:(id)object {
Class modelClass = [object class];
GYDataContextQueue *queue = [self queueForDBName:[modelClass dbName]];
[queue dispatchSync:^{
if (object.isSaving) {
return;
}
[(id)object setValue:@YES forKey:@"saving"];
[_dbRunner saveObject:object];
NSMutableDictionary *cache = [self tableCacheFromDBCache:queue.cache class:modelClass];
if (cache) {
[cache setObject:object forKey:[(id)object valueForKey:[modelClass primaryKey]]];
}
[(id)object setValue:@NO forKey:@"saving"];
}];
}
먼저 디스크 에 저장 한 다음 메모리 에 캐 시 합 니 다.쓰기 과정 에서 object 의 saving 필드 를 YES 로 설정 합 니 다. 이 방법 을 여러 번 호출 할 때 동시에 쓰 는 것 을 방지 하 는 것 처럼 보이 지만 직렬 대기 열 이 라면 이런 문제 가 없 을 것 입 니 다. 개인 적 으로 는 소 용이 없다 고 생각 합 니 다.
3. 삭제 작업
- (void)deleteObject:(Class)modelClass
primaryKey:(id)primaryKey {
GYDataContextQueue *queue = [self queueForDBName:[modelClass dbName]];
[queue dispatchSync:^{
NSMutableDictionary *cache = [self tableCacheFromDBCache:queue.cache class:modelClass];
id object = [cache objectForKey:primaryKey];
if (object) {
[cache removeObjectForKey:primaryKey];
[object setValue:@YES forKey:@"deleted"];
}
NSString *where = [self whereIdSqlForClass:modelClass];
[_dbRunner deleteClass:modelClass
where:where
arguments:@[ primaryKey ]];
}];
}
메모리 캐 시 를 삭제 하고 디스크 캐 시 를 삭제 합 니 다.주의해 야 할 것 은 이 대상 이 메모리 캐 시 에서 제거 되 었 지만 외부 에 서 는 변수 가 인용 되 어 방출 되 지 않 을 수 있 습 니 다. 대상 의 속성 deleted 를 YES 로 설정 하고 이 대상 이 삭제 되 었 음 을 나타 내 며 외부 에서 적당 한 시간 에 이 deleted 속성 을 판단 합 니 다.
4. 조작 수정
- (void)updateObject:(Class)modelClass set:(NSDictionary *)set primaryKey:(id)primaryKey {
GYDataContextQueue *queue = [self queueForDBName:[modelClass dbName]];
[queue dispatchSync:^{
NSMutableDictionary *cache = [self tableCacheFromDBCache:queue.cache class:modelClass];
[cache removeObjectForKey:primaryKey];
NSString *where = [self whereIdSqlForClass:modelClass];
[_dbRunner updateClass:modelClass set:set where:where arguments:@[ primaryKey ]];
}];
}
메모리 에 있 는 캐 시 를 먼저 삭제 하고 디스크 에 있 는 캐 시 를 업데이트 합 니 다.이 때 이 대상 의 메모리 캐 시가 없어 졌 습 니 다. 다음 조회 작업 을 할 때 다시 디스크 에 가서 최신 대상 을 조회 하고 메모리 에 캐 시 합 니 다.여 기 는 왜 메모리 캐 시 를 직접 업데이트 하지 않 고 오히려 구 부 러 졌 습 니까?인터페이스 디자인 의 문제 인 것 같 습 니 다. 여기 모델 클 라 스 는 하나의 대상 이 아니 라 하나의 유형 으로 직접 사용 할 수 없습니다.
GYDB Runner 는 데이터베이스 의 읽 기와 쓰기, 사무 처리 등 을 쓰 고 있 으 며, 다음은 데이터베이스 의 특성 점 1, 자동 일괄 쓰기 입 니 다.
- (void)autoTransactionForDatabaseInfo:(GYDatabaseInfo *)databaseInfo {
databaseInfo.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, [databaseInfo.databaseQueue queue]);
if (databaseInfo.timer) {
[databaseInfo.databaseQueue asyncInDatabase:^(FMDatabase *db) {
[db beginTransaction];
}];
dispatch_source_set_timer(databaseInfo.timer,
dispatch_time(DISPATCH_TIME_NOW, kTransactionTimeInterval * NSEC_PER_SEC),
kTransactionTimeInterval * NSEC_PER_SEC,
NSEC_PER_MSEC);
dispatch_source_set_event_handler(databaseInfo.timer, ^{
if (databaseInfo.needCommitTransaction) {
[databaseInfo.databaseQueue syncInDatabase:^(FMDatabase *db) {
[db commit];
[db beginTransaction];
}];
databaseInfo.needCommitTransaction = NO;
}
});
dispatch_resume(databaseInfo.timer);
}
}
타 이 머 를 켜 고 트 랜 잭 션 을 켜 면 1s 마다 이 시간 동안 의 모든 트 랜 잭 션 을 자동 으로 제출 합 니 다.물론 모든 작업 에 사물 이 필요 한 것 은 아 닙 니 다. 삭제 수정 할 때 databaseInfo. needCommitTransaction 은 YES 로 설정 되 어야 트 랜 잭 션 제출 을 통 해 데이터 뱅 크 의 정확성 을 확보 하고 조회 작업 을 할 때 트 랜 잭 션 이 없습니다.수 동 으로 사 무 를 추가 하지 않 으 면 SQLite 는 모든 SQL 의 실행 을 위해 사 무 를 만 들 고 성능 을 소모 합 니 다.여러 개의 SQL 실행 패 키 지 를 하나의 업무 에 포함 시 키 고 1s 마다 제출 하여 여러 개의 사 무 를 만 드 는 비용 을 피 할 수 있 습 니 다.읽 기와 쓰기 가 빈번 할 때 성능 이 크게 향상 된다.
2. 데이터베이스 테이블 을 자동 으로 생 성하 고 업데이트 할 때 데이터베이스 작업 을 수행 할 때 현재 대상 모델 이 지속 적 으로 저장 해 야 하 는 속성 을 비교 하고 데이터베이스 에 저 장 된 대상 의 속성 과 차이 점 을 비교 합 니 다. 현재 대상 속성 이 증가 할 때의 자동 업데이트 데이터베이스 테이블 구조 만 지원 하고 필드 를 삭제, 수정 하 는 데 무력 합 니 다. 이때 자신 이 새로 만 든 테이블 로 데이터 이전 을 완성 해 야 합 니 다.
3. 관계 형 property 와 faulting 은 데이터베이스 에서 Employee 를 조회 할 때 특정한 속성 depart. ment 에 대응 하 는 것 이 다른 관계 대상 Department 인 것 을 발견 하면 Department 를 조회 하지 않 고 Department 대상 을 만 들 고 department 속성 을 설정 하여 Employee 의 department 속성 이 Department 를 가리 키 도록 합 니 다.이 때 Department 대상 에 표 시 를 하고 fault 속성 을 YES 로 설정 합 니 다. Employee 의 depart. ment 속성 을 진정 으로 사용 할 때 해당 Department 의 fault 속성 이 YES 인 것 을 발견 하고 초기 화 되 지 않 은 값 임 을 알 고 데이터베이스 Department 를 찾 습 니 다.GYDataContext 의 조회 조작 을 구체화 해 보도 록 하 겠 습 니 다.
- (id)getObject:(Class)modelClass properties:(NSArray*)properties
primaryKey:(id)primaryKey {
GYDataContextQueue *queue = [self queueForDBName:[modelClass dbName]];
__block id object = nil;
[queue dispatchSync:^{
NSMutableDictionary *cache = [self tableCacheFromDBCache:queue.cache class:modelClass];
object = [cache objectForKey:primaryKey];
if (!object || ((id)object).isFault) {// ......@2
NSString *where = [self whereIdSqlForClass:modelClass];
NSArray *objects = [_dbRunner objectsOfClass:modelClass
properties:properties
where:where
arguments:@[ primaryKey ]];
object = [objects firstObject];
if (object && !properties.count) {
[cache setObject:object forKey:primaryKey];
}
}
}];
return object;
}
처음에 Employee 대상 을 조 회 했 을 때 매개 변수 modelClass 는 Employee 이 고 @ 2 조건 은 object 가 nil 이 므 로 데이터베이스 에 가서 Employee 대상 을 조회 합 니 다. 내부 에서 Employee. department 가 가리 키 는 Department 대상 을 국부 적 으로 예화 하고 캐 시 합 니 다. isFault 를 YES 로 설정 하고 동시에 Employee. department 가 이 대상 을 가리 키 도록 합 니 다.사용자 가 Employee. department 에 구체 적 으로 사용 할 때 이 방법 에 다시 들 어 갑 니 다. 이때 매개 변수 modelclast 는 Department 대상 입 니 다.캐 시 를 찾 아 대응 하 는 대상 을 찾 았 으 나 isFault 가 YES 인 것 을 발견 하고 초기 화 되 지 않 은 대상 을 위해 데이터 베 이 스 를 찾 아 실례 화 되 었 습 니 다.Faulting 메커니즘 은 대상 을 꺼 낼 때 모든 관계 대상 과 관계 대상 의 관계 대상 을 꺼 내 는 것 을 피한다.이렇게 하면 조회 속 도 를 높 여 로드 에 필요 한 대상 을 지연 시 킬 수 있다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.