[MOBILE-006][기초] 로컬 저장·캐시·오프라인 흐름 이해하기 > IT 기술 공유

본문 바로가기
사이트 내 전체검색

IT 기술 공유

[MOBILE-006][기초] 로컬 저장·캐시·오프라인 흐름 이해하기

페이지 정보

profile_image
작성자 기술팀장
댓글 0건 조회 137회 작성일 26-09-02 06:35

본문

[이번 수업]
모바일 네트워크는 자주 끊기거나 느려집니다. 로컬 저장은 기기 안에 데이터를 남기는 일, 캐시는 재생성 가능한 복사본, 오프라인 지원은 연결 없이 핵심 기능을 쓰게 하는 설계입니다. 로컬 데이터베이스에 캐시와 전송 대기열을 저장해 봅니다.

[선수지식]
MOBILE-004의 화면 상태와 MOBILE-005의 네트워크 오류를 알면 좋습니다. Python과 간단한 SQL을 읽으면 충분합니다.

[학습목표]
1. 설정·영구 데이터·캐시에 알맞은 저장 방식을 고른다.
2. 오프라인 읽기와 쓰기의 데이터 흐름을 설명한다.
3. 로컬 데이터와 전송 대기 작업을 트랜잭션으로 기록한다.

[핵심개념]
작은 설정은 키-값, 구조화 데이터는 데이터베이스, 큰 내용은 앱 전용 파일에 둡니다. 캐시는 다시 만들 수 있어 삭제돼도 핵심 기능이 망가지면 안 됩니다. 작성 초안·미전송 주문은 영구 데이터입니다. 저장 시각·버전·ETag와 만료 정책으로 오래된 캐시를 알립니다.

오프라인 우선 읽기는 화면이 로컬 원천을 읽고, 저장소가 서버 자료를 로컬에 반영하게 합니다. 빈 캐시·오래된 캐시·동기화 중을 구분합니다.

오프라인 쓰기는 사용자 변경과 아웃박스(outbox, 나중에 보낼 작업 목록)를 같은 트랜잭션에 저장합니다. 트랜잭션은 여러 변경을 전부 성공하거나 취소하는 묶음입니다. 재연결 뒤 `pending` 작업을 보내고 성공한 항목만 `synced`로 바꿉니다. 고유 ID, 재시도 상한, 지수 백오프로 중복과 과도한 호출을 막습니다. 여러 기기의 변경에는 버전·시각·사용자 확인 같은 충돌 정책이 필요합니다.

[따라하기]
아래를 `offline_demo.py`로 저장합니다.

```python
import sqlite3

db = sqlite3.connect("mobile006_demo.sqlite3")
with db:
    db.execute("CREATE TABLE IF NOT EXISTS article_cache(id TEXT PRIMARY KEY, title TEXT, cached_at TEXT)")
    db.execute("CREATE TABLE IF NOT EXISTS outbox(id TEXT PRIMARY KEY, action TEXT, body TEXT, state TEXT)")
    db.execute(
        "INSERT OR REPLACE INTO article_cache VALUES (?, ?, ?)",
        ("article-1", "캐시된 글", "2026-09-02T00:00:00Z"),
    )
    db.execute(
        "INSERT OR REPLACE INTO outbox VALUES (?, ?, ?, ?)",
        ("op-1", "CREATE_NOTE", '{"text":"오프라인 메모"}', "pending"),
    )
    title = db.execute("SELECT title FROM article_cache WHERE id=?", ("article-1",)).fetchone()[0]
    pending = db.execute("SELECT count(*) FROM outbox WHERE state=?", ("pending",)).fetchone()[0]
db.close()
print(f"오프라인 읽기: {title}")
print(f"전송 대기: {pending}건")
```

macOS·Linux는 `python3 offline_demo.py`, Windows는 `python offline_demo.py`로 실행합니다. 현재 폴더에 `mobile006_demo.sqlite3`가 생깁니다.

```text
오프라인 읽기: 캐시된 글
전송 대기: 1건
```

`with db`는 두 저장을 한 트랜잭션으로 묶습니다. `?`와 값 튜플을 분리해 SQL 결합을 피합니다. 실제 앱은 캐시를 읽고 아웃박스를 동기화합니다.

[흔한 실수]
캐시 삭제 때 작성 데이터까지 지우지 않습니다. 연결 표시만으로 요청 성공을 가정하지 않습니다. 무한 재시도는 배터리와 데이터를 낭비합니다. 고유 ID 없는 재전송과 무조건 마지막 값으로 덮는 충돌 처리를 피합니다. 절대 저장 경로도 고정하지 않습니다.

[보안 주의]
앱 전용 저장소도 백업·디버그 환경에서 노출될 수 있습니다. 토큰과 암호화 키는 Android Keystore, iOS Keychain 같은 보안 저장소에 둡니다. 민감 데이터·로그를 최소화하고 백업·로그아웃 삭제 정책을 정합니다. SQL은 매개변수로 실행하며 실습에는 가상 데이터만 씁니다.

[직접 해볼 과제]
`article_cache`에 `expires_at`을 추가하고, 만료된 내용 옆에 `오래된 캐시`를 표시합니다. 네트워크는 호출하지 않습니다.

[확인문제]
1. 사용자가 작성한 미전송 초안을 일반 캐시로 취급하면 안 되는 이유는 무엇인가요?
2. 오프라인 쓰기에서 데이터와 아웃박스를 같은 트랜잭션에 넣는 이유는 무엇인가요?
3. 전송 작업에 고유 ID와 충돌 정책이 필요한 이유는 무엇인가요?

[다음 학습]
MOBILE-007에서는 알림, 백그라운드 작업, 딥링크가 앱 상태와 만나는 방식을 배웁니다.

[공식 참고 자료]
- 모바일 저장소 선택: https://developer.android.com/training/data-storage/
- 오프라인 우선 데이터 계층: https://developer.android.com/topic/architecture/data-layer/offline-first
- Python sqlite3: https://docs.python.org/3/library/sqlite3.html
- Android 보안 키 저장소: https://developer.android.com/privacy-and-security/keystore
- iOS Keychain 서비스: https://developer.apple.com/documentation/security/keychain-services

댓글목록

등록된 댓글이 없습니다.

회원로그인

회원가입

사이트 정보

회사명 : 회사명 / 대표 : 대표자명
주소 : OO도 OO시 OO구 OO동 123-45
사업자 등록번호 : 123-45-67890
전화 : 02-123-4567 팩스 : 02-123-4568
통신판매업신고번호 : 제 OO구 - 123호
개인정보관리책임자 : 정보책임자명

접속자집계

오늘
3,903
어제
6,862
최대
16,772
전체
769,854
Copyright © 소유하신 도메인. All rights reserved.