iPhone SQLite Database Basics
원본 출처 : http://wiht.link/sqlite_resources
번역자 : DELPAI(delpai at gmail.com)
번역날짜 : 2009년 3월 27일
번역자 이야기 : 너무 급하게 하는 바람에 오역이 있을 수도 있습니다. 오역이 있더라도 참고사항으로만 봐주시기 바랍니다. :) 고칠 부분이 있으면 댓글 남겨주세요.
iPhone SDK에 NDA가 추가됨을 기뻐하며, iPhone에서 SQLite를 이용하는 설명서를 작성하기로 마음을 먹었습니다.
이 설명서는 SQLite 데이터베이스의 기본적인 정보와, 데이터베이스 디자인을 할 때 고려해야될 사항들, 그리고 iPhone에서 응용프로그램의 필드형식을 결정할때 알아야 할 몇가지 특별한 사항에 대해서 설명을 할것입니다.
이 기본 설명서를 끝내시고 나면, 당신의 코드에 데이터베이스를 어떻게 interface 하는지 자세히 설명되어있는 iPhone dev center에서 SQLiteBooks 예제 코드를 보시기 바랍니다.
Step1 : SQLite Database File 생성하기
SQLite 데이터베이스 파일을 생성하는데는 많은 방법이 있습니다. 제가 발견한 가장 쉬운 방법은 SQLite Firefoxextension을 다운하는 것입니다. SQLite Firefox extension은 SQLite 데이터베이스를 생성하고관리하는 GUI 응용프로그램입니다. 이 설명서의 나머지는 이미 SQLite Firefox extension이 설치되어 있다고생각할 것입니다.
데이터베이스 생성하기 :
1. “New Database” 툴바 버튼을 클릭
2. 데이터베이스 파일이름을 입력
3. “OK” 클릭
그럼 데이터베이스를 저장하기 위한 디렉토리를 선택하는 화면이 나올것입니다. 가장 이상적인 저장장소는 당신의 XCode 프로젝트 디렉토리입니다.
Step 2: 데이터베이스 스키마 생성하기
이제 데이터베이스 테이블을 설정하도록 하겠습니다. 이 데이터베이스는 간단하게 두개의 테이블로 구성될 것입니다.
만 약 당신이 매우 커다란 물류창고 응용프로그램을 개발하고 있다면, “적합한”데이터베이스 디자인을 설명하는 교재를 참고하시기바랍니다. 그러나 Third normal form에 눈을 돌리기 전에, DBA/Database 응용프로그램 개발자로 다년간활동한 제가 선택한 몇가지 가이드라인을 공유하겠습니다.
2. 게다가 객체 속성에서, 모든 테이블은 기본키(primary key)로 알려진 단일 식별자(unique identifier)가 자동으로 채워지는 정수(integer)필드를 가져야 합니다.
3. 부모 테이블에 의존적인 모든 테이블은 자신의 부모 테이블을 참조할 수 있는 방법을 꼭 가져야합니다.(이것을 가끔씩 외래키(Foreign Key)라고 합니다.)
지 금 우리가 만들 응용프로그램은 두개의 model객체를 가집니다. 하나는 Recipe 객체이고, 나머지 하나는Ingredient 객체입니다. 각 recipe객체는 하나나 그 이상의 ingredient 자식 객체를 가질 수 있습니다.(위다이어그램에 그려진 파란 화살표가 이것을 뜻하고, 이것은 1대다관계(1-to many relationship)이라고 불립니다.)
Recipe 객체는 “name”과 “description”속성을 가집니다. 두 필드 모두 문자열(strings)이며, 데이터베이스 필드의VarChar(Variable length Character String)를 말합니다. 또한, Recipe 테이블은정수(Integer)형식의 “Recipe_ID” 필드가 있습니다. 이 필드는 Recipe 테이블의 기본키( Primarykey)입니다.
Ingredient 객체는 단 한개의 속성, “description” 을 가집니다. 해당 속성도VarChar입니다. Ingredient 테이블은 기본키(Primary key)인 “Ingredient_ID”를 가지며, 이기본키는 특정 ingredient를 참조할 수 있습니다.
마지막으로 Ingredient 테이블의”Recipe_ID” 필드는 Recipe 테이블을 참조하기 위한 외래키(Foreign Key)입니다. 이 외래키를 이용해서 어떤ingredient를 볼수 있고, 어떤 Recipe에 속하는 지 알 수 있습니다. 해당 응용프로그램은 대부분 이 키를 특정Recipe에 속한 ingredients를 얻기 위해 사용될 것입니다.
Recipe 테이블을 생성하도록 하겠습니다. 툴바 버튼의 “New Table”을 클릭하시면 아래와 같이 정보를 입력하실 수 있습니다.
“Recipe_ID” 필드를 위해 기본키(Primary Key)와 자동증가(Autoinc) 체크박스를 체크하시기 바랍니다. 기본키(PrimaryKey) 체크박스는 SQLIte가 해당 필드를 단일 인덱스(Unique Index)로 취급하는 것을 명시하고, 해당 필드의 값은중복되지 않고, 빠른 쿼리 처리를 위해 지속적으로 정렬되어 있을 것입니다.(나중에 확장 테이블을 추가하기 위한 효율적인 쿼리에대해서 이야기 하도록 하겠습니다.)
자동증가(Autoinc) 체크박스는 기본키(Primary key)값의 자동생성을다루고 있습니다. 자동증가(Autoinc) 체크박스가 체크가 되지 않으면, 새로운 로우(Row)가 추가되더라도 현재 제일 높은기본키(Primary Key)보다 더 높은 기본키를 설정할 것입니다. 자동증가(Autoinc) 체크박스가 체크되어 있으면테이블이 가진 가장 높은 기본키(Primary KEy)보다 하나 더 높은 키본키를 설정할 것입니다. 이 체크박스는 당신이 어떻게레코드를 삭제하는지에 따라 세팅할지 않할지 결정할 수 있습니다.
Ingredient테이블은 다음과 같습니다.
Ingredient 테이블처럼 “Recipe_ID”에 기본키로 체크하지 않습니다. 왜냐하면 “Recipe_ID”는 Recipe 테이블의 기본키이지Ingredient테이블의 기본키가 아닙니다.(이 키는 외래키(Foreign Key)라고도 불립니다.)
마지 막으로데이터베이스 스키마에 할 작업은 Ingredient테이블의 “Recipe_ID”에 인덱스(Index)를 생성하는 것입니다. 이테이블에 포함된 쿼리 대부분은 “Recipe_ID”필드의 특정 값을 찾을 것입니다. 이 인덱스(Index)는 이 필드를 찾는데빠른 속도향상을 줄것입니다.(참고: Ingredient 테이블에 많은 양의 레코드가 존재하지 않으면 특별한 속도 향상을 체감할수없을 것이나, 이 것은 좋은 디자인 방법이므로, 어쨋든 인덱스를 생성하도록 하겠습니다.)
마 지막으로 테이블에 몇 개의 데이터를 넣어야 합니다. SQLite Manager에서 테이블을 선택하고 “Add newRecord” 버튼을 클릭해서 넣을 수도 있고, Insert 쿼리를 만들어서 “Execute SQL”탭을 이용해 데이터를 추가할수 있습니다.
다음은 Recipe 테이블에 추가될 예제 데이터입니다.
Recipe_ID | Name | Description |
1 | Omelet | A delicious and eggy breakfast. |
2 | Grilled Cheese Sandwich | A delicious and cheese filled lunch. |
3 | Pizza | A classic dinner from the old world. |
다음 3개의 Insert 쿼리로 추가할 수 있습니다.
INSERT into Recipes(Name, Description) VALUES(’Grilled Cheese Sandwich’, ‘A delicious and cheese filled lunch.’);
INSERT into Recipes(Name, Description) VALUES(’Pizza’, ‘A classic dinner from the old world.’);
해당 쿼리에는 Recipe_ID 필드에 값을 넣지 않습니다. 위에서 말한 대로 이 값은 기본키로써 자동적으로 데이터베이스가 계산하여 넣을 것입니다.
다음은 Ingredient 테이블입니다.
Ingredient_ID | Recipe_ID | Description |
1 | 1 | Eggs |
2 | 1 | Water |
3 | 1 | Salt |
4 | 2 | Bread |
5 | 2 | Cheese |
6 | 2 | Butter |
7 | 3 | Pizza Dough |
8 | 3 | Pizza Sauce |
9 | 3 | Cheese |
10 | 3 | Toppings |
다음 쿼리로도 넣을 수 있습니다.
INSERT into Ingredients(Recipe_ID, Description) VALUES(1, ‘Water’);
INSERT into Ingredients(Recipe_ID, Description) VALUES(1, ‘Salt’);
INSERT into Ingredients(Recipe_ID, Description) VALUES(2, ‘Bread’);
…
INSERT into Ingredients(Recipe_ID, Description) VALUES(3, ‘Toppings’);
다시 한번 말하지만, 이 테이블의 기본키인 “Ingredient_ID”는 추가하지 않았습니다. 그러나 외래키인 “Recipe_ID”는 추가하였습니다.
Step 3: XCode 프로젝트에 데이터베이스 파일 추가하기
데이터베이스 파일을 추가하기 위해서는 “Resources” 폴더에서 오른쪽 마우스를 클릭하고, “Add->Existing Files…”를 선택합니다. 그리고 방금 생성한 데이터베이스 파일을 추가합니다.
XCode 는 자동적으로 당신이 선택한 파일을 “Copy Bundle Resources”에 추가합니다.(응용프로그램이 컴파일될때, 선택한데이터베이스 파일은 자동적으로 응용프로그램 번들 리소스(Application Bundle’s Resouce 폴더에 저장하여,응용프로그램이 접근할수 있도록 합니다.)
추가사항 : Jonathan Wight씨는 XCode project에직접적으로 SQLite 데이터베이스 파일을 삽입하는 것보다, SQL 소스 파일을 프로젝트에 삽입하고 XCode가 db 파일을생성할수 있도록 컴파일 방식을 설정하여, 컴파일할때 번들(bundle)에 삽입되는 것을 제안하였습니다. 그의 제안은 소스 코드제어와 관련된 몇가지 이점을 가지고 잇습니다. 다음은 그가 제공한 예제 입니다.
Step 4 : SQLite Library 연결하기
마 지막으로 우리는 모든 SQLite 함수가 포함된 라이브러리를 연결할 준비가 되어 있습니다. 해당 라이브러리를 추가하기 위해서는XCode project의 “Frameworks”에서 오른쪽 마우스를 클릭하고, “Add->ExistingFrameworks…”를 선택합니다.
그 리고 iPhoneSDK 폴더를 열고, “usr/lib/libsqlite3.0.dylib”파일을 선택합니다.(해당 폴더의 다른libsqlite*.lib 파일들과 헷갈리지 마세요, 그것들은 libsqlite3.0.dylib의 별명(aliases)입니다.)
이제 SQLite code를 작성할 준비가 되어있습니다.(다시한번 말씀드리지만, SQLiteBooks 예제 코드를 보시기 바랍니다.)
추 가사항 : Jonathan Wight씨는 Framework방식을 이용하는 것보다 SQLite library를 연결하기 위해서”Project Settings”의 “Build” 탭에 있는 “Other Linker Flags”세팅을 이용하는 것이 더 좋다고말합니다. 이것은 아래와 같이 “-lsqlite3” flag를 추가하면 됩니다.
이 방법은 어떤 플랫폼을 대상으로 하든지 정확하기 라이브러리를 연결할 수 있는 이점이 있습니다.
iPhone의 SQLite의 미묘한 차이점
1. 실제 iPhone에 있는 SQLite는 시뮬레이터보다 매우 느립니다. 시뮬레이터에서 잠깐 깜빡거릴 정도의 쿼리는 실제 장치에서 몇 초가 더 걸립니다.
2. 만약 데이터베이스에 쓰고 싶다면, 당신이 쓸수 있는 장소에 먼저 복사를 하시기 바랍니다. SQLiteBooks 예제 코드를 보시면 어떻게 하시는지 나와있습니다.
3. “Full text search”같은 SQLite 추가기능은 iPhone SQLite 라이브러리에 컴파일되지 않습니다.
4. 미래를 위해 준비하세요! 만약 데이터베이스에 특정 테이블이나 필드에 의존하는 기능을 추가하고 싶으시면 데이터베이스디자인을 부분적으로 하시기 바랍니다. 이것은 당신이 응용프로그램 업데이트를 할때 당신의 데이터베이스에 필요한 SQL 명령어를쓰는 시간은 단축시켜 줄 것입니다.