태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

데이터베이스 이용하기 - (2) 안드로이드 데이터베이스 기초

2009.07.04 16:37


이번 강좌에서는 안드로이드 어플리케이션 내에서 실제로 데이터베이스를 다루는 방법에 대하여 알아보도록 하겠습니다. 데이터베이스는 워낙에 양도 많고, 이해하고 넘어가야 하는 것들도 많아서 강좌를 진행하는데 어려운 점이 한둘이 아니네요. -_-;;
차근차근~ 들어가도록 하겠습니다.

다른 강좌도 마찬가지지만, 데이터베이스 쪽 강좌를 보실 때는 절대 서두르지 마세요. 전 서둘러서 하다가 -_-;; 오히려 머리만 복잡해지고! 되는 건 없고! 한참동안 방황했었답니다~ ^^;; 마치 코드의 늪에 빠진 기분이 들어군요;; 분명히 맞게 입력한 것 같은데 에러나고...-_-;; 게다가 에러의 대부분이 런타임 에러여서 도통 무엇 때문인지 감도 잘 안오고 말이죠. ㄱ-..

주저리는 여기서 마치도록 하고, 본격적으로 강좌에 들어가도록 하겠습니다.

데이터베이스의 간단한 구성 : 테이블, 레코드, 필드

데이터베이스를 구성하는 요소는 참으로 다양하지만, 자주 쓰이는 것들은 기본적인 것들 몇 가지들입니다. 

1. 테이블


  테이블은 데이터들이 저장되어 있는 공간입니다. 테이블은 특정 주제에 관련된 데이터들을 담고 있으므로, 하나의 데이터베이스 내에는 여러 개의 테이블이 존재할 수 있습니다. 

2. 필드



필드는 각 항목의 "분류" 정도로 보면 되겠습니다. 전화번호부의 이름, 전화번호, 이메일주소 등이 필드에 해당됩니다.

3. 레코드



레코드는 하나의 항목과 관련된 필드의 값의 집합입니다. 예를 들면 위의 그림에서는 _id가 2, name은 google, phone은 12345 인 데이터의 집합이 하나의 레코드입니다. 이것 뿐 아니라 나머지 하이라이트된 4개 항목도 모두 레코드이지요. 전화번호부를 예로 들자면, 한 사람이 가지고 있는 데이터들(이름, 전화번호, 이메일주소)을 레코드라 할 수 있습니다.


안드로이드에서 데이터베이스 다루기 : 데이터베이스 어댑터

  데이터베이스를 생성하고, 열고, 데이터베이스에 데이터를 넣고, 쿼리를 통해서 데이터베이스에서 정보를 받아오는 작업은 SQLiteDatabase(android.database.sqlite.SQLiteDatabase) 와 SQLiteOpenHelper(android.database.sqlite.SQLiteOpenHelper) 내의 메소드를 통해 처리됩니다.

  SQLiteDatabase 클래스에서는 데이터베이스를 다루는 작업(추가, 삭제, 수정, 쿼리)를 담당하고, SQLiteOpenHelper 클래스에스는 데이터베이스의 생성, 열기, 업그레이드를 담당합니다. 이러한 클래스 내의 메소드를 통해 직접 데이터베이스를 생성하고, 수정하고, 쿼리를 수행할 수도 있지만 이렇게 할 경우 코드상에 데이터베이스 구조들도 다 드러나게 되고, 실제로 코드를 볼 때에도 이 코드가 무엇을 하는 코드인지 바로 보기 불편합니다. 그래서, 일반적으로는 내가 사용할 데이터베이스에 맞게끔 데이터베이스 어댑터를 만들고 어댑터를 통해 데이터베이스를 관리합니다.


데이터베이스에서 원하는 자료를 받아오기 : 쿼리(query; 질의)

  데이터베이스를 생성하고 자료를 추가하는 것 못지않게 중요한 것이 바로 자신이 원하는 데이터베이스를 가져오는 것입니다. 이는 쿼리(Query; 질의)를 통해 이루어집니다. 질의 결과는 Cursor객체 형태로 반환됩니다.

public Cursor query (String table, String[] columns, String selection, String[] selectionArgs,
String groupBy, String having, String orderBy, String limit)

  • table  질의를 수행할 테이블 이름입니다.
  • columns  자료를 받아올 필드들입니다. null을 입력하면 모든 필드를 반환합니다.
  • selection  SQL의 "where" 구문에 해당되는 조건을 입력합니다. 조건이 많을 경우, ?로 대체합니다.
  • selectionArgs  selection을 ?로 지정하였을 경우, 그 조건들을 입력합니다.
  • groupBy  SQL의 "group by"구문에 해당합니다.
  • having  groupBy를 지정했을 경우, 그 조건을 넣어줍니다.
  • orderBy  결과값 정렬 방식을 지정합니다. null을 입력하면 기본 정렬을 수행합니다.
  • limit  결과값의 개수를 제한합니다.

(API : android.database.sqlite.SQLiteDatabase)
위에서 소개된 형태 외에도 다른 형태로 2가지 메소드가 있으니 참조하시면 됩니다.

예제)
                // 모든 레코드를 반환하는 쿼리를 실행합니다.
	Cursor all = myDB.query("data", null, null, null, null, null, null, null);
                // 이름이 google인 레코드를 반환하는 쿼리를 실행합니다.
	Cursor sel = myDB.query("data", "name = google", null, null, null, null, null, null);


데이터베이스 값을 가지는 객체, Cursors와 ContentValues

  데이터베이스 내에서 값을 추가하고, 삭제하고, 수정하는 작업돠는 별도로, 데이터베이스에 저장된 값을 코드 내로 가져와야 하거나, 코드 내에서 받은 값들을 데이터베이스에 추가시키는 과정이 있습니다. 우선, 데이터베이스의 데이터를 코드 내로 가져오는 것부터 보도록 하겠습니다.

데이터베이스 -> 코드 데이터 가져오기 : Cursor

  데이터베이스에서 자료를 가져올 때는 그 자료가 특정한 값 하나 (예:이름)이 될 수도 있고, 레코드가 될 수도 있고, 혹은 전체 데이터가 될 수도 있습니다. 이런 자료들을 받아오기 위해서 Cursor 인터페이스를 사용합니다.
  커서는 쿼리(질의) 결과로 나온 레코드들을 가리키는, 말 그대로 마우스 "커서" 처럼 특정 레코드를 가리키는 역할을 합니다. 결과 레코드가 여러 개일 경우, 커서를 이리저리 움직이면서 여러 레코드들의 데이터들을 받아올 수 있습니다.


데이터베이스에서 커서는 특정 레코드를 가리키는 역할을 합니다.



Cursor 인터페이스의 주요 메소드는 다음과 같습니다.

  • moveToFirst  커서가 쿼리(질의) 결과 레코드들 중에서 가장 처음에 위치한 레코드를 가리키도록 합니다.
  • moveToNext  다음 레코드로 커서를 이동합니다.
  • moveToPrevious  이전 레코드로 커서를 이동합니다.
  • getCount  질의 결과값(레코드)의 갯수를 반환합니다.
  • getColumnIndexOrThrow  특정 필드의 인덱스값을 반환하며, 필드가 존재하지 않을경우 예외를 발생시킵니다.
  • getColumnName  특정 인덱스값에 해당하는 필드 이름을 반환합니다.
  • getColumnNames  필드 이름들을 String 배열 형태로 반환합니다.
  • moveToPosition  커서를 특정 레코드로 이동시킵니다.
  • getPosition  커서가 현재 가리키고 있는 위치를 반환합니다.

커서에서 데이터를 받아올 때에는,  get<데이터타입>(필드 인덱스) 메소드를 사용합니다.
위의 그림과 같은 질의 결과에서 이름을 받아오고 싶다면, 우선 이름 필드(name)의 인덱스를 알야아 합니다. 필드 인덱스는 일반적인 인덱스들과 마찬가지로 0부터 시작하므로 _id의 필드 인덱스는 0, name은 1, phone은 2가 되겠습니다. 참고로, 위 데이터베이스의 각 필드별 데이터 타입은 _id는 long, name은 String, phone은 long입니다.

필드 인덱스는 알았고, 받아올 데이터 타입이 String이므로 현재 레코드에서 이름을 받아오기 위해서는 getString(int ColumnIndex)메소드를 사용하면 됩니다. 즉, getString(1)이 되겠죠. 만약, 이름이 아니라 전화번호를 받아오고 싶다면 getLong(2)을 사용하면 되겠죠?

	// 레코드로부터 이름을 받아옵니다.
	String name = result.getString(1);
	// 레코드로부터 전화번호를 받아옵니다.
	long phone = result.getLong(2);


다른 데이터타입을 불러오는 메소드는 여기를 참조하세요.


코드 -> 데이터베이스에 자료 입력하기 : ContentValues

(android.content.ContentValues)
위의 Cursor와는 반대로, 자료를 데이터베이스에 입력하기 위해서 ContentValues 객체를 데이터베이스의 레코드와 동일하게 사용합니다. ContentValues 객체에 데이터베이스 테이블에 맞게 자료를 입력한 후, SQLiteDatabase 클래스의 insert()메소드를 사용하여 데이터베이스에 새로운 레코드를 추가합니다.

Cursor 형태로 된 쿼리 결과에서 데이터를 가져오는 것과 비슷하게, put(_필드 이름_, _입력할 값_)을 이용합니다.

	// 필요한 데이터를 입력합니다.
	ContentValues newValues = new ContentValues();
	newValues.put("name", "구글");
	newValues.put("phone", "1234567");
	// 레코드를 추가합니다.
	myDB.insert("data", null, newValues);

데이터베이스에 레코드를 추가하는 메소드인 insert()메소드에 대해 자세한 정보는 여기를 참고하세요.

이번 강좌에서는 안드로이드에서 데이터베이스를 다루기 위해 필요한 이론들을 다뤄봤습니다. 기본적으로 데이터베이스를 다루는 방법은 알아봤으니, 다음 강좌에서는 데이터베이스 어댑터를 만들고, 실제로 데이터베이스를 생성하고 관리하는 것에 대해 다루어보도록 하겠습니다.
저작자 표시 비영리 변경 금지
신고

커니 데이터 관리/SQLite3 , , , , , ,

  1. 이전 댓글 더보기
  2. Blog Icon
    마창

    커니님~~ 질문만드려서 죄송해요~

    sql사용안하구 안드로이드 에뮬레이터를 아예 종료하고 다시켜도
    데이터가 저장되게 할 수 있는 간단한 방법은 없을까요
    static 선언해주면 에뮬레이터구동시킨후에는 데이터가 유지되는데
    에뮬레이터 종료하고 다시키면 자료가 리셋되서...
    예를 들어서 int 배열값을 계속 저장시키는 방법이 없을까요..
    알구계시면 답변점 부탁드릴께요~

  3. Blog Icon
    진스

    안드로이드가 기본적으로 제공하는 DB에 대해서는 볼 수 없을까요?
    예를 들어서 phonebook 의 DB 라던가 하는 것들이요.
    sqlite3로 해봐도 보기가 어렵네요..ㅠㅠ;;

  4. 안드로이드의 기본 DB의 구조를 보기보다는, 기본 제공하는 Content Provider를 이용하는 것이 낫지 않을까 생각합니다. 어차피 DB 구조를 알아봤자 그 DB에 Direct로 접근해서 정보를 얻어올 수는 없거든요.

  5. Blog Icon

    다른 강좌도 마찬가지지만, 데이터베이스 쪽 강좌를 보실 때는 절대 서두르지 마세요. 전 서둘러서 하다가 -_-;; 오히려 머리만 복잡해지고! 되는 건 없고! 한참동안 방황했었답니다~ ^^;; 마치 코드의 늪에 빠진 기분이 들어군요;; 분명히 맞게 입력한 것 같은데 에러나고...-_-;; 게다가 에러의 대부분이 런타임 에러여서 도통 무엇 때문인지 감도 잘 안오고 말이죠. ㄱ-..

    커니님의 이말 100000% 공감합니다...
    디비는 마치... 삽질의 페스티벌 같아요..............(에러하나 잡는데 하루가 더 넘게 걸리더군요..)
    꼭 천천히 하나하나 다 알고 넘어가야 되는 것 같습니다..ㅠ.ㅜ

  6. Blog Icon

    비밀댓글입니다

  7. 컨텐트 프로바이더만으로 접근한다면 컨텐트 프로바이더 자체에서 그러한 기능을 제공해주지 않는 이상 쉽게 쓰기는 어려울 것 같습니다.

  8. Blog Icon
    신발끈

    안녕하세요 안드로이드 프로그래밍 하면서 자주 참고하고 있습니다^^ 질문이 있는데요~
    파일내에 values.put("name", "홍길동";); 이런 식으로 데이터 삽입을 했는데, 이 어플을 실행하고 끝낼때 DB가 매번 생기고 없어지는지 궁금합니다. 어플의 DB를 어떻게 관리해야하는지 궁금합니다.

  9. 일반적으로 한번 생성되고 나면 삭제되지 않습니다.
    다만 DB 버전을 업그레이드 하셨다면 데이터베이스 어댑터 내의 onUpgrade() 메서드가 호출되면서 변경 내용에 따라 수정을 하도록 할 수 있습니다.

  10. Blog Icon
    jong327

    일단 설명은 참 잘해주셨는데 edittext같은곳에서 정보를 입력해서 db에 저장시키는 예제나, 그러한 예를 든 강좌였으면 어땠을까 싶어요 ㅠㅠㅠ 저는 너무도 이해가 안가서 예제가 필요한뎅...

    혹시 쓸만한 예제 파일이나 자료 있으신가요 ㅠ?

    jong404@gmail.com 이쪽으로 부탁드립니다!

    저는 지금 a 액티비티에서 edittext에 내용물을 입력후, b라는 곳에서는 textview로 띄우며, c라는 곳에서는 리스트로 그것들을 표현하는 앱을 개발중에 있습니다 ㅠㅠ 정말 막막하기만한데 데드라인은 내일이고 -_-;;

    아무튼 유익한 자료 있으시다면 부탁드립니다!

  11. Blog Icon
    이십사

    = _= 아... 이 부분에서 좀 끙끙대고 있네요. ㅠ

  12. Blog Icon

    비밀댓글입니다

  13. 앗... 2가 맞습니다 제보 감사합니다!

  14. Blog Icon

    비밀댓글입니다

  15. Blog Icon
    Adelposs

    아... 보기에는 쉬워보이는데 하면 할 수록 끙끙하거리고 있네요 ㅜㅜ

  16. Blog Icon
    serenasun

    오!!이해가 조금 되네요~ㅎㅎ 궁금한게 있는데요~ query로 데이터를 받아와서 cursor로 담아내잖아요~ 이때 cursor를 null로 초기화를 안해줘도 상관이 없을까요??

  17. Blog Icon
    급한사람

    Cursor sel = myDB.query("data", null, null, null, null, null, null, null);같은 명령에서
    ORDER BY부분에 null을 넣지않고 오름차순이나 내림차순할때는 어떤식으로 하나요
    phone을 기준으로 정렬할때의 예문을 좀 알려주세요

  18. API 문서를 참고하세요.

    public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)

    Since: API Level 1
    Query the given table, returning a Cursor over the result set.
    Parameters

    table
    The table name to compile the query against.

    columns
    A list of which columns to return. Passing null will return all columns, which is discouraged to prevent reading data from storage that isn't going to be used.

    selection
    A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given table.

    selectionArgs
    You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings.

    groupBy
    filter declaring how to group rows, formatted as an SQL GROUP BY clause (excluding the GROUP BY itself). Passing null will cause the rows to not be grouped.
    having A filter declare which row groups to include in the cursor, if row grouping is being used, formatted as an SQL HAVING clause (excluding the HAVING itself). Passing null will cause all row groups to be included, and is required when row grouping is not being used.

    orderBy
    How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered.

  19. Blog Icon
    이 강좌가 짱입니다.

    책3권들고 인터넷 예제 다 찾아봐도 다 어이없게 설명해놨는데 이 강좌 보고 제대로 이해 됬습니다. 나중에 제대로 이해하면 책 3권 불태워 버릴겁니다....(근데 이 강좌 보고도 못하면 어쩌지?)

  20. Blog Icon
    worstlie

    막연히 앱을 만들고싶다는 마음으로 시작했는데 아무것도 갈피를 못잡고있었는데 많은 도움이 됐습니다^^ 아직 전체내용의 2할밖에 이해가 안되지만 여러번 반복해서 학습하고 온전히 제걸로 가져가겠습니다. 좋은 지식나눔 감사합니다;)

  21. 좋은글 출처를 표시하고 블로그에 담아갑니다. ^^

  22. 후아 ㅠㅠ 데이터베이스 진짜 너무 어렵네여 ㅠㅠ 프로젝트 처음 개발하는데 이제 겨우 만들었나 싶었는데 데이터베이스에서 꽝 막혀가지구 ........ㅜㅜ 데이터베이스에 이미지 파일 불러오게끔 하려면 어떻게 해야하는지 질문좀 드려도 될까여 ?/ ㅠㅠ

  23. 담아갈게요~

  24. 담아갈께요 ~!
    http://share9.tistory.com/

  25. Blog Icon

    비밀댓글입니다

  26. 언제 보아도 간결하고 쉬우면서 자상한 설명 기억하고 있습니다.
    들러서 훑어보다가 일부 내용은 베껴 갑니다.
    수고해서 작성하신 글인데, 발췌한 내용 제 블로그에 올려도 될까요?
    감사합니다.