본문 바로가기
Javascript study

[JS] IndexedDB

by 카누가 좋아요 2023. 8. 27.

📌 참고 사이트

IndexedDB에 대해 알아보자 (velog.io)

 

IndexedDB에 대해 알아보자

IndexedDB 간단 정리

velog.io

 

IndexedDB 사용하기 - Web API | MDN (mozilla.org)

 

IndexedDB 사용하기 - Web API | MDN

IndexedDB는 사용자의 브라우저에 데이터를 영구적으로 저장할 수 있는 방법 중 하나입니다. IndexedDB를 사용하여 네트워크 상태에 상관없이 풍부한 쿼리 기능을 이용할 수 있는 웹 어플리케이션을

developer.mozilla.org

 

[DB기초] 트랜잭션이란 무엇인가? (tistory.com)

 

[DB기초] 트랜잭션이란 무엇인가?

트랜잭션의 정의 트랜잭션(Transaction)은 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산들을 의미한다. 트

coding-factory.tistory.com

 

 

 

📋 IndexedDB란?

사용자의 브라우저에 데이터를 영구적으로 저장할 수 있는 방법 중 하나이다.

IndexedDB를 사용하면 네트워크 기능에 상관 없이 풍부한 쿼리 기능을 이용할 수 있는 웹 어플리케이션을 만들 수 있다.

(* 쿼리 : 데이터베이스에 정보를 요청하는 것으로, 웹 서버에 특정한 정보를 보여달라는 웹 클라이언트 요청(주로 문자열 기반)에 의한 처리를 말한다.)

 

 

📍 IndexedDB의 특징

➡️ 보통 HDD 용량의 50%로 많은 양의 구조화된 데이터를 클라이언트에 저장할 수 있다. (10MB 의 용량을 가지고 있는 local storage에 비하면 많은 양의 데이터를 저장할 수 있다.)

➡️ JS 기반의 객체 지향 데이터베이스로, JS가 인식 가능한 자료형과 객체를 저장 가능하다.

➡️ 트랜잭션을 사용하고, key-value 쌍의 데이터베이스이다.

➡️ 비동기 API에 속한다.

 

❓ 트랜잭션

데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위를 의미한다.

사용자가 시스템에 대한 서비스 요구 시 시스템이 응답하기 위한 상태 변환 과정의 작업 단위라고 할 수 있다.

하나의 트랜잭션은 Commit(작업 성공)되거나 Rollback(비정상이 감지되었을 때 모든 연산 취소)된다.

 

 

 

📋 IndexedDB 사용하기

IndexedDB가 권장하는 기본 패턴은 다음과 같다.

 

1️⃣ 데이터베이스를 연다.

2️⃣ 객체 저장소(Obejct store)를 생성한다.

3️⃣ 트랜잭션(Transaction)을 시작하고 데이터를 추가하거나 읽어들이는 등의 데이터베이스 작업을 요청한다.

4️⃣ DOM EventListener를 사용해 요청이 완료될 때까지 기다린다.

5️⃣ 요청 객체에서 찾을 수 있는 결과를 가지고 무언가를 한다.

 

 

📍 데이터베이스 열기

IndexedDB.open(데이터베이스 이름, 버전) 함수를 통해 데이터베이스를 연다.

 

➡️ 이 open 함수를 사용하면 이벤트로 처리한 결과(성공 상태)오류 값이 있는 IDBOpenRequest 객체를 반환한다. 즉, open 함수의 결과는 IDBDatabase의 인스턴스이다.

 

➡️ open 메서드의 두 번째 매개 변수는 데이터베이스의 버전으로, 데이터베이스 안의 객체 저장소와 그것들의 구조(데이터베이스 스키마)를 결정한다.

 

➡️ 데이터베이스가 아직 존재하지 않으면 open에 의해 생성되고, 그 다음 onupgradeneeded 이벤트가 트리거되고 이 이벤트 안에서 데이터베이스 스키마를 작성한다.

 

요청(request)에 대해 성공했을 때, 또는 에러가 발생했을 때 제어를 할 객체를 생성해야 한다.

➡️ onsuccess : NameVersion이 일치하는 데이터베이스가 있는 경우 호출된다.

➡️ error : Name이 일치하지만 존재하즌 DB의 Version보다 낮은 Version을 호출하면 에러가 발생한다.

 

// indexedDB.open(Name, version)의 형식으로 데이터베이스 열기
const request = indexedDB('notes', 2);

// onupgradeneeded 메서드로 데이터베이스 스키마 작성하기
// Name 또는 Version과 일치하는 데이터베이스가 없는 경우 onupgradeneeded가 호출된다.
request.onupgradeneeded = e => {
  alert('upgrade is called');
}

 

 

📍 Object Store 생성

createObjectStore(tableName, keyPath) 함수를 이용하면 현재 데이터베이스에 테이블 형태로 저장되는 객체 저장소를 생성할 수 있다.

 

request.onupgradeneeded = (e) => {
  // e.target.result는 데이터베이스 스키마를 생성하거나 업그레이드하는 작업을 수행하기 위해 
  // 사용되는 데이터베이스 연결 객체를 가리킨다.
  db = e.target.result;
  // memo라는 객체 저장소를 생성하고, 각 데이터 항목의 key값으로 id를 사용하도록 정의하였다.
  var objectStore = db.createObjectStore('memo', {keyPath: 'id});
}

 

 

📍 데이터 추가하기

transaction 함수(transaction(객체 저장소명, 트랜잭션 모드)transaction을 시작하고, objectStore() 함수객체 저장소를 선택하고 add() 함수로 원하는 객체를 추가한다.

이때 transaction의 인자로는 읽고 쓰기가 가능하도록 하여 데이터를 추가하거나 수정하도록 만들기 위해 'readwrite'를 넣어 주어야 한다.

(transaction 함수는 어떤 객체 저장소를 대상으로 어떤 작업을 수행할지를 명시해 주기 위해 사용한다고 생각하면 된다.)

 

const memos = [
  {id: 1, name: 'Lee', age: 12, text: "I don't want to go to school."},
  {id: 2, name: 'Kim', age: 25, text: "I don't want to go to work."}
];

// db라는 데이터베이스 객체에서 'memo'라는 객체 저장소에 접근하고, 해당 저장소에 대한 쓰기 권한을 가진 트랜잭션 생성
// objectStore('memo')는 트랜잭션 내에서 'memo' 객체 저장소에 접근할 수 있게 해준다.
var memoObjectStore = db.transaction('memo', 'readwrite').objectStore('memo');
// memo 객체 저장소에 memos 배열 안의 객체들이 추가된다.
memos.forEach(function(memo) {
  memoObjectStore.add(memo);
});

 

❗ 주의할 점은 key에 해당하는 id 값을 동일하게 작성하였다면 ConstraintError(데이터베이스에서 제약 조건을 위반한 경우 발생하는 오류)를 마주할 수 있다.

(예를 들어 memos 배열의 객체의 id 값을 모두 1로 설정하는 경우)

 

 

📍 데이터 읽기

transaction()의 기본 값read only이기 때문에 데이터 읽기 시에는 적어주지 않아도 된다.

get()을 이용해 데이터를 읽을 수 있다.

 

// memo 객체 저장소에 대해 읽기 권한을 가진 트랜잭션 생성, 트랜잭션 내에서 memo 객체 저장소에 접근
var memoObjectStore = db.transaction('memo').objectStore('memo');

// memoObjectStore에서 key 값이(위의 경우 id값이) '1' 인 데이터 항목을 검색하라는 뜻이다. 
var request = memoObjectStore.get('1');

// 검색에 오류가 생기면 오류 발생 알리기
request.onerror = e => {
  alert('Error is called');
}

// 검색이 성공하면 검색 결과로 나온 데이터의 name과 text의 값 알리기
request.onsuccess = e => {
  alert(`Name: ${request.result.name}, Text: ${request.result.text}`);
}

 

 

📍 데이터 업데이트

transaction()readwrite 모드로 설정해주고, put()을 이용해 이미 존재하는 데이터를 업데이트 할 수 있다.

 

// memo 객체 저장소에 대해 readwirte 모드로 접근해 트랜잭션을 생성하고, 
// 그 트랜잭션 내에서 memo 객체 저장소에 접근한다.
let memoObjectStore = db.transaction('memo', 'readwrite').objectStore('memo');

// memoObejctStore에서 key값이 (id가) 1인 데이터가 있는지 탐색한다.
let request = memoObjectStore.get('1');

// 에러 발생 시 에러 발생을 알린다.
request.onerror = e => {
  alert('Error is called');
};

// 데이터를 찾는 데 성공하면
request.onsuccess = e => {
  // data 객체는 reuqest의 결과인 request.result이다.
  let data = request.result;
  // data의 text의 값을 변경한다.
  data.text = "I don't want to travel";
  // put 메서드에 인자로 변경된 data 객체를 넣어주어 데이터를 업데이트한다.
  let requestUpdate = memoObjectStore.put(data);
  
  // 데이터 업데이트 과정에서 에러가 발생할 경우 아래 문구 띄우기
  requestUpdate.onerror = e => {
    alert('Error is called');
  }
  
  // 데이터 업데이트가 정상적으로 완료되면 아래 문구를 띄운다.
  requestUpdate.onsuccess = e => {
    alert('Success Updating');
  }
}

 

 

📍 Cursor 사용하기

get()을 이용해 데이터를 조회하려면 key를 알고 있어야 한다.

그런데 key를 모르는 상태에서 전체 데이터를 조회하려면 cursor를 이용하면 된다.

커서는 객체 저장소 내의 데이터 항목을 순차적으로 탐색하기 위한 도구이다.

openCursor()를 사용하면 저장소 내의 첫 번째 데이터 항목을 가리키는 커서를 열고 반환한다.

이후에 커서를 사용해 다음 데이터 항목으로 이동하거나 데이터를 읽어올 수 있다.

continue() 메서드를 이용해 다음 값을 조회할 수 있다.

 

// 값을 조회하는 것이므로 transaction은 기본 모드인 readonly로 생성
// 해당 트랜잭션 내에서 memo 객체 저장소에 접근
let objectStore = db.transaction('memo').objectStore('memo');

// 커서 열기
let request = objectStore.openCursor();

// 커서가 제대로 열리지 않으면 에러 메시지 띄우기
request.onerror = e => {
  alert('Error with opening cursor!' + e.target.error);
}

// 커서가 제대로 열린 경우
request.onsuccess = e => {
  // cursor에 데이터 할당하기 (커서가 열린 상태에서 cursor가 다음 데이터로 이동하도록 함)
  let cursor = e.target.result;
  
  // cursor에 할당된 데이터가 있을 경우
  if (cursor) {
    // cursor의 key와 value에서의 name, text를 띄우기
    alert(`Key: ${cursor.key}, Name: ${cursor.value.name}, Text: ${cursor.value.text}`);
    // 다음 데이터로 넘어가기
    cursor.continue();
  }
  // 커서의 데이터를 다 조회한 경우
  else {
    // 데이터가 더 없다고 문구 띄우기
    alert('No more entries!');
  }
}

 

* getAll 메서드를 이용해 전체 값을 조회할 수도 있지만 이는 IndexedDB의 표준이 아니고 추후 없어질 가능성이 있기 때문에 권장하고 있지 않다.

'Javascript study' 카테고리의 다른 글

[JS] fetch  (0) 2023.09.03
[JS] Promise  (0) 2023.08.28
[JS] Closure  (0) 2023.08.27
[JS] 실행 컨텍스트 (2)  (0) 2023.08.25
[JS] 실행 컨텍스트 (1)  (0) 2023.08.25

댓글