냐냐한 IT/냐냐한 실습 기록

IndexedDB API: IndexedDB 주요 특징 및 기본 용어

소소하냐 2022. 11. 16. 15:04
MDN 원문 참조 : IndexedDB key characteristics and basic terminology 
날짜 : 2022.11.16 (문서 내용은 계속 변경되는 부분이라 정리한 날짜를 함께 기록)

위 참조 링크 내용을 정리하였습니다. 


이 문서는 IndexedDB의 주요 특징과, IndexedDB API를 이해하기 위한 몇 가지 필수 용어를 소개 

 

유용한 문서들 : 

* Using IndexedDB(원문), IndexedDB 사용-1.개요(정리) : API 사용 방법에 대한 자세한 튜토리얼 

* IndexedDB API(원문), IndexedDB:개요(정리) : IndexedDB에서 사용하는 객체 유형을 문서화한 메인 페이지와 하위 페이지들 참고 

* Browser storage limits and eviction criteria(원문) : 브라우저가 백그라운드에서 데이터 저장 처리를 어떻게 하는지에 대한 내용


주요 특징 (Key characteristics)

- 사용자의 브라우저 내부에 데이터를 지속적으로 저장

- 네트워크 가용성과 상관없이, 온라인과 오프라인 모두에서 작동하는 풍부한 쿼리 기능이 있는 웹 응용프로그램 생성 가능

- 많은 양의 데이터(예:대출 도서관의 DVD 카탈로그)를 저장하고, 지속적인 인터넷 연결이 필요하지 않은(예: 메일 클라이언트, 할일 목록, 메모장) 애플리케이션에 유용 

 

- "key"로 색인되는 객체를 저장 / 조회 가능 

- 데이터베이스의 모든 변경은 트랜잭션 내에서 발생 

- 동일 출처 정책(Same Origin Policy) (도메인 내에 저장된 데이터에만 접근 가능)

 

다른 데이터베이스처럼 IndexedDB를 사용하면 문제가 생길 수 있음.

다음의 주요 특징 알아두기 :

 

* key-value 쌍으로 저장 

   - value : 복잡한 구조의 객체 가능  (정리자 덧, value : { ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com" } ) 

   - key : 해당 객체의 속성이 가능 (정리자 덧, 위 value 객체의 ssn 속성이 key가 될수 있음) 

   - 빠른 검색, 정렬을 위해 객체의 모든 속성을 사용하는 index 생성 가능 

   - key는 binary 객체 가능 

 

* 트랜잭션 데이터베이스 모델 기반 

   - IndexedDB에서 수행하는 모든 것은 트랜잭션에서 발생 

   - IndexedDB API는 인덱스, 테이블, 커서 등을 나타내는 많은 객체들을 제공, 하지만 이들은 각각 특정 트랜잭션에 연결됨 

   - 트랜잭션 외부에서 명령어를 실행하거나 커서를 여는 것은 불가능 

   - 트랜잭션에 정의된 수명에 의해, 완료 후에 트랜잭션을 사용하려고 하면 예외가 발생 

   - 트랜잭션은 자동으로 커밋 됨 (수동으로 커밋 불가) 

   - 이러한 트랜잭션 모델은 사용자가 두개의 서로 다른 탭에서 프로그램을 열 경우를 고려하면 매우 유용 

   - 참고 : Wikipedia article on transactions, 아래 transaction 정의 부분 

 

* 대부분 비동기(asynchronous)

   - API는 반환값(return value)으로 데이터를 주지 않고, 콜백 함수로 전달 

   - 데이터베이스에 값을 "저장"하거나 동기(synchronous)적인 수단을 통해 데이터베이스의 값을 "검색"하지 않음 

     => 대신, 데이터베이스 작업이 발생하도록 "요청(request)"함 

   - 동작이 완료되면 DOM 이벤트로 받고, 성공 / 실패 여부는 이벤트의 type으로 알 수 있음

      (XMLHttpRequest 작동 방식과 유사) 

 

* 많은 요청(request)을 사용 

   - 요청은 성공/실패 DOM 이벤트를 받는 객체 

   - onsuccessonerror 속성(property)이 있고, addEventListener()removeEventListener()로 호출할 수 있음 

   - 요청 상태에 대한 readyState, result, errorCode 속성이 있음 

   - result 속성은 요청이 생성된 방법에 따라 여러가지로 달라짐 (예, IDBCursor 인스턴스, 또는 insert된 값의 key) 

 

* result를 사용할 수 있을 때 DOM 이벤트를 사용하여 알림

   - DOM 이벤트에는 항상 type 속성이 있음 (IndexedDB에서는, 일반적으로 "success" 또는 "error"로 설정됨)

   - DOM 이벤트에는 항상 이벤트의 향하는 곳(where the event is headed)을 나타내는 target 속성이 있음

   - 대부분의 경우 이벤트의 target은 어떤 데이터베이스 작업의 결과로 생성된 IDBRequest object  

   - 성공 이벤트는 버블링되지 않고, 취소할 수 없음. 

   - 에러 이벤트는 버블링되고, 취소가 가능 

   - 에러 이벤트는 취소되지 않는 한, 실행 중인 모든 트랜잭션을 중단 한다. (중요) 

 

* 객체 지향 (object-oriented) 

   - row와 colum의 집합인 테이블인이 있는 관계형 데이터베이스가 아니다.

   - (관계형 데이터 저장소에는, 명명된 데이터 타입의 colum과 데이터의 row 집합으로 저장된 테이블이 있다)

   - IndexedDB에서는 데이터 타입에 대한 객체 저장소(object store)를 생성하고, 해당 저장소에 JavaScript 객체를 지속한다. 

   - 각 객체 저장소는 쿼리와 반복을 효율적으로 만들어주는 인덱스들을 가질 수 있음 

   - 참고 : Wikipedia article on object database 

 

* Structured Query Language(SQL)를 사용하지 않음 

   - 결과 집합에서 반복하기 위해 사용하는 cursor를 생성하는 index에 대한 쿼리를 사용 

     (원문: It uses queries on an index that produces a cursor, which you use to iterate across the result set.) 

   - 참고 : Wikipedia article on NoSQL

 

* 동일 출처 정책(same-origin policy) 

   - 출처(origin)는 스크립트가 실행되는 문서의 domain, 응용프로그램 계층 protocol, URL의 port  

   - 각 출처는, 자신의 고유한 연관된 데이터베이스 집합이 있음 

   - 각 데이터베이스는 출처 내에서 식별할 수 있는 이름이 있음 

   - IndexedDB의 보안은 다른 출처의 데이터에 접근하는 것을 방지

   - 예, http://www.example.com/app/ 은 http://www.example.com/dir/ 에서 데이터 조회가 가능  

   - 예, http://www.example.com:8080/dir/(다른 port) 또는 https://www.example.com/dir/(다른 protocol)은 http://www.example.com/dir/ 에서 데이터 조회가 불가능 

 

Note : 브라우저가 서드파티 쿠키를 허용하지 않도록 설정하지 않는 한, 서드파티 윈도우 컨텐츠(예: <iframe> 컨텐츠)는 내장된 IndexedDB store에 접근이 가능(bug 1147821 확인) 

 

제한 사항 (Limitations) 

IndexedDB는 클라이언트 측 스토리지에 필요한 대부분의 경우를 처리하도록 설계되었지만, 다음과 같은 몇 가지 경우는 설계되지 않음 : 

 

   * 다국어/국제화(Internationalize)된 정렬 

      - 모든 언어가 동일하게 문자열 정렬을 하지 않기 때문에 지원되지 않음. 

      - 특정 국제화 순서로의 저장은 안되지만, 데이터베이스에서 읽은 데이터를 직접 정렬하는 것은 가능.   

      - Note : 지역-인식 정렬(locale-aware sorting)이 firefox 43 이후로 활성화 flag로 허용됨 (현재는 Firefox에서만) 

   * 동기화 (Synchronizing) 

      - 서버측 데이터베이스와 동기화를 처리하도록 설계되지 않음. 

      - 동기화하는 코드 작성이 필요 

   * 전체 텍스트 검색 (Full text searching)

      - SQL의 LIKE 연산자에 해당하는 것이 없음 

 

또한, 브라우저는 다음 같은 상황에서 데이터베이스를 지울 수 있음 : 

 

   * 사용자의 삭제 요청. 많은 브라우저에는 쿠키, 북마크, 저장된 암호 및 IndexedDB 데이터를 포함한 특정 웹사이트에 저장된 모든 데이터를 사용자가 지울 수 있는 설정이 있음 

   * private browsing mode. (몇몇 브라우저는 "private browsing"(Firefox) 또는 "incognito"(Chrome) 모드가 있음). 세션이 끝나면 브라우저는 데이터베이스를 삭제함 (정리자 덧, 크롬을 새 시크릿 창으로 열어서 Database 생성 및 종료해보면 확인 가능) 

   * 디스크 또는 할당량 한도에 도달 

   * 데이터 손상 

   * 기능에 호환되지 않는 변경 

 

정확한 상황과 브라우저의 기능은 시간이 지나면 변하지만, 브라우저 벤더들의 전반적인 철학은 가능한한 데이터를 유지하기 위해 최선을 다하는 것 

 

 

 

 


핵심 용어 (Core terminology)

이 섹션에서는 IndexedDB API를 이해에 관련된 핵심 용어를  정의하고 설명한다. 

 

Database 

 

database 

일반적으로 하나 이상의 object store로 구성된, 정보 저장소(repository). 각 데이터베이스에는 다음과 같은 내용이 있어야 함 : 

   * 이름(Name) : 특정 출처(origin)에서 데이터베이스를 식별하고 수명 동안 일정하게 유지됨. 이름은 어떤 문자열도 가능(빈 문자 포함)

   * 현재 버전(Current version) : 데이터베이스가 처음 생성될 때, 따로 지정하지 않으면 버전은 정수 1. 각 데이터베이스는 주어진 시간에 하나의 버전만 가질 수 있음. 

 

database connection 

 

데이터베이스를 열어서 생성된 작업. 주어진 데이터베이스는 동시에 여러 연결을 가질 수 있다. 

 

durable (튼튼한, 영속성 있는) 

 

Firefox에서 IndexedDB는 내구성이 있었다, 즉 readwrite 트랜잭션에서 모든 데이터가 디스크에 플러시된 것이 보장된 경우에만 완료 이벤트가 발생했다. 

 

Firefox 40부터, 다른 IndexedDB를 지원하는 브라우저와 동일하게, IndexedDB 트랜잭션은 성능 향상을 위해 내구성 보장을 완화했다(bug 1112702 확인). 이 경우, OS가 데이터를 쓰라고 명령한 후에 완료 이벤트가 발생하지만 잠재적으로 데이터가 실로 디스크에 플러시 되기 전에 발생한다. 따라서 이전보다 빠르게 이벤트가 전달될 수 있지만, 디스크에 데이터가 플러시되기 전에 OS가 충돌하거나, 시스템 전원이 손실되는 경우 전체 트랜잭션이 손실될 가능성은 적다. (원문:The event may thus be delivered quicker than before, however, there exists a small chance that the entire transaction will be lost if the OS crashes or there is a loss of system power before the data is flushed to disk.)

이러한 치명적인 이벤트들은 드물기 때문에, 대부분의 소비자는 더 이상 고려할 필요가 없다. 

 

Note : Firefox에서는, 어떤 이유로(예: 나중에 재계산할 수 없는 중요한 데이터를 저장) 내구성을 보장하려는 경우, 실험적(비표준) readwriteflush 모드로 트랜잭션을 생성해서, 완료 이벤트가 전달되기 전에 디스크에 플러시하도록 트랜잭션을 강제할 수 있다 (IDBDatabase.transaction 확인). 이것은 현재 실험적이며, about:config에서  dom.indexedDB.experimental pref가 true로 설정된 경우에만 가능. 

index 

- 인덱스는 참조된 object store에서 레코드를 찾기 위한 특수한 object store

- 인덱스는 레코드의 value 부분이 참조된 object store의 key인 영구 key-value 저장소 

   - 정리자 덧, 아래 gif에서 개발자도구 > 애플리케이션 > IndexedDB

      > toDoList(데이터베이스)

      > toDoList(참조된 object store) : key(taskTitle), value: {taskTitle, hours, minutes, day ... } 

      > hours / minutes / day ... (index) : 저장소의 value인 hours, minutes, day ...가 key가 됨 

      (https://mdn.github.io/dom-examples/to-do-notifications/ > 개발자 도구에서 확인 가능) 

toDoList의 index (hours / minutes / day ...) 확인

- 참조된 object store의 레코드가 추가/수정/삭제될 때 마다 인덱스의 레코드는 자동으로 채워짐

- 인덱스의 각 레코드는 참조 store object에서 오직 하나의 레코드만을 가리킬 수 있지만, 여러 인덱스는 동일한 object store를 참조 가능 

- object store가 변경되면, object store를 참조하고 있는 모든 인덱스들은 자동으로 업데이트 됨

 

- 또는, key를 사용해서 object store에서 레코드를 찾을 수도 있음

- 참조 : Using IndexedDB(원문), IndexedDB 사용 - 개요(정리), IDBKeyRange

 

object store 

- 데이터베이스에 데이터가 저장되는 메커니즘 

- object store는 key-value 쌍의 레코드를 지속적으로 보유 

- object store내의 레코드는 key에 따라 오름차순으로 정렬

 

- 모든 object store는 해당 데이터베이스내에서 고유한 이름을 가져야 함

- object store는 선택적으로 key generator와 key path를 가질 수 있음 

- object store에 key path가 있으면 in-line key를 사용하는 것, 그렇지 않으면, out-of-line key를 사용하는 것

 

- 참조 : IDBObjectStore

 

request 

- 데이터베이스에서 읽기, 쓰기 작업을 한다. 

- 모든 요청(request)는 하나의 읽기 또는 쓰기 작업으로 나타냄. 

 

transaction 

- 특정 데이터베이스에 대한 데이터-접근과 데이터-수정 작업의 원자(atomic) 집합

- 데이터베이스의 데이터와 상호 작용하는 방법

- 데이터베이스에서의 데이터의 모든 읽기/쓰기는 트랜잭션에서 발생해야 함 

 

- 데이터베이스 연결은 한번에 연결된 여러개의 활성(active) 트랜잭션을 가질 수 있다, 쓰기 트랜잭션 범위가 겹쳐지지 않는 한. 

- 생성시에 정의된 트랜잭션 범위(scope)는, 트랜잭션이 상호 작용할 object store를 결정하고 트랜잭션의 수명동안 일정하게 유지 됨 

- 예를 들면, 데이터베이스 연결에 이미 flyingMonkey object store만 포함하는 범위의 쓰기 트랜잭션이 있는 경우, unicornCentaurunicornPegasus object store 범위인 두번째 트랜잭션을 시작할 수 있다. 

- 읽기 트랜잭션의 경우, 여러개를 가질 수 있다  심지어 겹치는 트랜젹션도 있음  

 

- 트랜잭션은 짧은 수명이 예상되므로, 브라우저는 오래-실행되는 트랜잭션이 잠근 스토리지 리소스를 풀기 위해서, 너무 오래 걸리는 트랜잭션을 종료할 수 있다. 

- 트랜잭션에서 데이터베이스에 대한 변경을 롤백하는 트랜잭션을 중단할 수 있다. 

   (원문 : You can abort the transaction, which rolls back the changes made to the database in the transaction.) 

- 트랜잭션을 시작하거나 중단 하기 위해 활성화되는 것을 기다릴 필요 조차 없음 

   (원문 : And you don't even have to wait for the transaction to start or be active to abort it.) 

 

- 3가지 모드 : readwrite, readonly, versionchange 

- object store와 index를 생성하고 삭제하는 유일한 방법은 versionchange 트랜잭션을 사용하는 것 

- 참조 : IndexedDB(원문)IndexedDB API:Intro(정리)

- 모든 것이 트랜잭션에서 발생하기 때문에, IndexedDB에서 매우 중요한 개념이다. 

- 참조 : IDBTransaction

 

version 

- 데이터베이스가 처음 생성될 때 버전은 정수 1. 

- 각 데이터베이스는 한번에 하나의 버전; 한번에 여러 버전으로 존재할 수 없음. 

- 버전을 변경하는 유일한 방법은 현재 버전보다 높은 버전으로 open  

 

Key and value 

in-line key 

- 저장된 value의 일부분으로 저장된 key  

- key path를 사용하여 찾는다  

- in-line key는 generator를 사용하여 생성 가능

- key가 생성된 후에, key path를 사용하여 value에 저장하거나 key로 사용할 수도 있음 

 

key 

- object store에 저장된 값들을 구성하고 검색하는 데이터 값(value)

- object store는 key generator, key path, 명시적으로 지정된 value 세개의 소스 중 하나에서 key를 얻을 수 있다.

- key는 이전 key보다 큰 숫자를 가진 데이터 타입이어야 함 

- 동일한 object store에서 각 레코드는 고유한 key를 가진다. (동일한 object store에 같은 키를 가진 여러 레코드는 불가능) 

 

- key로 사용 가능한 type : string, date, float, a binary blob, array 

- array의 경우, key는 빈 값에서 부터 무한대까지 범위가 가능 

- 배열 안에 배열 포함 가능

 

- 또한, index를 사용하여 object store에서 레코드 검색도 가능 

key generator 

- 순서대로 새로운 key를 생성하기 위한 메커니즘

- object store에 key generator가 없으면, 응용프로그램은 레코드를 저장을 위해 key를 제공해야 한다. 

- generator는 저장소간 공유되지 않는다. 

- 웹 개발에서는, 실제로 key generator를 생성하거나 액세스하지 않기 때문에, 브라우저 구현 세부사항에 더 가까움

 

key path 

- 브라우저가 object store 또는 index에서 key를 추출할 위치를 정의

- 유효한 key path는 다음 중 하나를 포함 : 빈 문자열, JavaScript 식별자, 마침표로 구분된 여러 JavaScript 식별자, 또는 이들 중 하나를 포함하는 배열 (an empty string, a JavaScript identifier, or multiple JavaScript identifiers separated by periods or an array containing any of those) 

- 공백(space)은 포함 불가 

 

out-of-line key 

- 저장되는 value와 분리되어 저장되는 key 

 

value 

- 각 레코드에는 boolean, number, string, date, object, array, regexp, undefined, null을 포함하여 JavaScript에서 표현할 수 있는 것을 포함할 수 있는 value가 있다. 

- object 또는 배열이 저장될 때, 해당 object 또는 배열의 속성(property) 및 값(value)은 유효한 모든 값이 가능 

- blob 및 file 저장 가능 (specification

 

Range and scope 

cursor 

- key 범위로 여러 레코드를 반복하기 위한 메커니즘

- 커서는 반복중인 인덱스 또는 object store를 나타내는 source를 가진다. 

- 범위 내에서 위치(position)를 가지고, 레코드 키의 순서대로 증가/감소하는 방향(direction)으로 이동

- 참조 : IDBCursor 

key range 

 

- key에 사용되는 일부 데이터 타입에 대한 연속 간격 

- key 또는 key의 범위를 사용하여 object store와 index에서 레코드 조회 

- lower / upper 바운드를 사용하여 범위를 제한하거나 필터링 

- 예를 들어, x와 y 사이의 모든 key 값을 반복

- 참고 : IDBKeyRange.

scope 

- 트랜잭션이 적용되는 object store와 인덱스 집합

- read-only 트랜잭션의 범위는 동시에 겹치면서(overlap) 실행 가능 

- 반면에, writing 트랜잭션의 범위는 겹칠 수 없다. 

- 여전히 동일한 범위로 여러 트랜잭션을 동시에 실행할 수 있지만, 대기열에 추가되고 차례로 실행 


Next steps 

IndexedDB의 주요 특징과 핵심 용어를 이해하면, 더 구체적인 내용을 얻을 수 있다. API 사용 방법에 대한 튜토리얼은  Using IndexedDB(원문), IndexedDB 사용-1.개요(정리) 를 참조 

 


IndexedDB 정리 목록

IndexedDB API: Intro (개요)

IndexedDB API: IndexedDB 사용 - 1 (개요)

IndexedDB API: IndexedDB 사용 - 2 (저장소(store) 생성 및 구조화)

IndexedDB API: IndexedDB 사용 - 3 (데이터 추가, 검색, 제거)

IndexedDB API: IndexedDB 사용 - 4 (버전 변경 시 다른 탭, 보안, 브라우저 종료 시 경고 등 나머지 내용)

IndexedDB API: IndexedDB 주요 특징 및 기본 용어