반응형

 데이터베이트(database)에 데이터를 저장하는 것은 마치 주소록 정보같이, 반복되고 구조화된 데이터에 가장 이상적인 방법입니다.

이번 시간은 여러분이 일반적인 SQL 데이터베이스를 잘 알고 있다고 가정하고 설명할 것이며 안드로이드에서의 SQLite 데이터베이스(database)를 시작하는 데 도움이 되고자 합니다. 여러분이 Android 에서 데이터베이스(database)를 사용하는데 필요한 API 들은android.database.sqlite 패키지안에 있습니다.



스키마(Schema) 정의와 Contract (Define a Schema and Contract)

-----------------------------------------------------

 SQL 데이터베이스의 주요 법칙중 하나는 스키마(schema)입니다. 스키마(schema)는 데이터 베이스가 어떻게 구성되어 있는가에 대한 공식적인 선언입니다. 스키마는 여러분이 여러분의 데이터베이스(database)를 생성하는데 사용하는 SQL 문을 나타냅니다. 여러분은 명시적이고 자기 문서화 하는 방법으로 스키마의 레이아웃을 지정하는 Contract 클래스로 알려진 companion 클래스을 생성하는데 유용한 것을 찾게 될 겁니다. 


contract 클래스는 URIs, 테이블, 컬룸(Column)에 대한 이름을 정의한 상수에 대한 컨테이너(container) 입니다. contract 클래스는 같은 패키지 안에 있는 모든 다른 클래스를 통틀어 같은 상수를 사용하도록 합니다. 이것은 여러분인 하나의 장소(위치)에서 컬룸(Column)의 이름을 변경하도록 하며, 그것을 가지고 있는 있는 여러분의 코드 전체에 변경 사항이 반영되도록 합니다.


contract 클래스를 조직하는 좋은 방법은 클래스의 루트(root)레벨에 여러분의 전체 데이터베이스(database)를 전역(global)으로 정의해 놓는 것입니다. 그런 다음 컬룸(column)을 열거한 각 테이블에 대한 이너 클래스(inner class)을 만듭니다.


Note : BaseColumns 인터페이스(interface)를 구현함으로서, 여러분의 이너클래스(inner class)는 cursor adapter 같은 일부 안드로이드 클래스들이 가지고 있을 것으로 기대하고 있는 _ID라고 불려지는 주요 키(프라이머리 키 : primary key)를 상속할 수 있습니다. 이것이 반드시 필요하지는 않지만, 이를 통해 여러분이 Android 프레임워크(framework)와 조화롭게 데이터베이스를 작업할 수 있도록 도와 줍니다.



아래는 단일 테이블에 대해 테이블 이름과 컬룸(column) 이름을 정의하는 부분의 예제입니다.

 public final class FeedReaderContract {

    // To prevent someone from accidentally instantiating the contract class,

    // give it an empty constructor.

    public FeedReaderContract() {}


    /* Inner class that defines the table contents */

    public static abstract class FeedEntry implements BaseColumns {

        public static final String TABLE_NAME = "entry";

        public static final String COLUMN_NAME_ENTRY_ID = "entryid";

        public static final String COLUMN_NAME_TITLE = "title";

        public static final String COLUMN_NAME_SUBTITLE = "subtitle";

        ...

    }

}




SQL Helper를 사용하여 데이터베이스 생성하기

(Create a Database Using a SQL Helper)

--------------------------------------

여러분이 데이터베이스의 모양을 정의할 때, 여러분은 데이터베이스(database)와 테이블(table)을 생성하고 유지하는 메소드들을 구현해야만 합니다. 아래 테이블을 만들고 삭제하는 몇가지 전형적인 명세서(statment)이 있습니다.

 private static final String TEXT_TYPE = " TEXT";

private static final String COMMA_SEP = ",";

private static final String SQL_CREATE_ENTRIES =

    "CREATE TABLE " + FeedEntry.TABLE_NAME + " (" +

    FeedEntry._ID + " INTEGER PRIMARY KEY," +

    FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +

    FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +

    ... // Any other options for the CREATE command

    " )";


private static final String SQL_DELETE_ENTRIES =

    "DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;


 여러분이 단말기의 내부저장소(internal storage)에 저장하는 파일처럼, 안드로이드는 여러분의 데이터베이스(database)를 어플과 관련된 프라이빗(private) 디스크(disk)의 공간에 저장합니다. 여러분의 데이터는 안전합니다. 왜냐하면, 기본적으로 이 영역은 다른 어플들이 접근할 수 없기 때문입니다.



유용한 API들은 SQLiteOpenHelper 클래스에서 사용할 수 있습니니다. 여러분이 데이터베이스(database)를 참조하는 인스턴스를 얻기위해 이 클래스를 사용할때, 시스템은 데이터베이스를 생성하고 업데이트하는 명령같이 오래 걸리는 명령들을 수행할 수도 있기에 오직 데이터베이스가 필요할 때만 사용되며 startup하는 동안에는 수행하지 않습니다. 여러분이 해야할 모든 것은 getWirteableDatabase() 또는 getReadableDatabase()를 호출하는 것입니다.


Note : getWriteableDatabase() 또는 getReadableDatabase() 역시 오래 걸릴 수 있게 때문에, AsyncTask 또는IntentService 와 같이 백그라운드 스레드(Background Thread)안에서 호출해야 합니다.


SQLiteOpenHelper 를 사용하기 위해, onCreate()onUpgrade() 그리고 onOpen() 콜백 메소드들을 오버라이드(override)한 하위클래스(subclass)를 생성합니다. 여러분이 onDowngrade() 를 구현할지도 모르지만, 꼭 요구 되지는 않습니다.



아래는 위에 소개된 명령 중 일부를 사용하는 SQLiteOpenHelper의 구현에 대한 예제입니다.

 public class FeedReaderDbHelper extends SQLiteOpenHelper {

    // If you change the database schema, you must increment the database version.

    public static final int DATABASE_VERSION = 1;

    public static final String DATABASE_NAME = "FeedReader.db";


    public FeedReaderDbHelper(Context context) {

        super(context, DATABASE_NAME, null, DATABASE_VERSION);

    }

    public void onCreate(SQLiteDatabase db) {

        db.execSQL(SQL_CREATE_ENTRIES);

    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        // This database is only a cache for online data, so its upgrade policy is

        // to simply to discard the data and start over

        db.execSQL(SQL_DELETE_ENTRIES);

        onCreate(db);

    }

    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        onUpgrade(db, oldVersion, newVersion);

    }

}


여러분의 데이터베이스에 접속하기 위해서는, SQLiteOpenHelper의 하위클래스(subclass)을 인스턴스화 합니다.

  FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());




데이터베이스에 정보 넣기( Put Information into a Database)

-------------------------------------------------

ContentVauses 객체를 insert()메소드의 매개변수로 전달함으로서 데이터베이스안에 데이터를 삽입합니다.

 // Gets the data repository in write mode

SQLiteDatabase db = mDbHelper.getWritableDatabase();


// Create a new map of values, where column names are the keys

ContentValues values = new ContentValues();

values.put(FeedEntry.COLUMN_NAME_ENTRY_ID, id);

values.put(FeedEntry.COLUMN_NAME_TITLE, title);

values.put(FeedEntry.COLUMN_NAME_CONTENT, content);


// Insert the new row, returning the primary key value of the new row

long newRowId;

newRowId = db.insert(

         FeedEntry.TABLE_NAME,

         FeedEntry.COLUMN_NAME_NULLABLE,

         values);


insert() 메소드의 첫번째 인자는 간단한 테이블 이름입니다. 두번째 인자는 컬룸(Column)의 이름을 제공합니다. 프레임워크(framework)는 ContentValues 가 비어있는 상황에서는 이곳에 NULL을 삽입할 수 있습니다.(만약 여러분이 넣을 값이 없어서, 이 곳을 null 로 대신하면 프레임워크(framework)는 row를 삽입하지 않습니다.)




데이터베이스에서 정보 읽기( Read Information from a Database)

-----------------------------------------------------

데이터 베이스로부터 정보를 읽기위해 query() 메소드를 사용하며, 이것에 여러분이 읽기를 원하는 컬룸(column)과 기준 selection을 전달 합니다. 이 메소드는 insert()  update()의 요소를 혼합한 것으로, 여러분이 삽입했던 데이터에 비해서 여러분이 원하는 데이터만 얻어오기 위해 컬룸(column) 목록중 원하지 않는 나머지는 제외합니다. query()의 결과는 Cursor 객체로 여러분에게 리턴됩니다.


 SQLiteDatabase db = mDbHelper.getReadableDatabase();


// Define a projection that specifies which columns from the database

// you will actually use after this query.

String[] projection = {

    FeedEntry._ID,

    FeedEntry.COLUMN_NAME_TITLE,

    FeedEntry.COLUMN_NAME_UPDATED,

    ...

    };


// How you want the results sorted in the resulting Cursor

String sortOrder =

    FeedEntry.COLUMN_NAME_UPDATED + " DESC";


Cursor c = db.query(

    FeedEntry.TABLE_NAME,  // The table to query

    projection,                              // The columns to return

    selection,                               // The columns for the WHERE clause

    selectionArgs,                          // The values for the WHERE clause

    null,                                      // don't group the rows

    null,                                      // don't filter by row groups

    sortOrder                                 // The sort order

    );


Cursor 안에 있는 row 를 보기위해서는 항상 값을 읽기 시작하기 전에 Cursor 이동 메소드중 하나를 호출해야만 합니다. 일반적으로 여러분은 query의 결과안에 있는 첫번째 데이터의 "읽기 위치"에 Cursor가 놓여지도록 moveToFirst() 메소드를 호출하여 시작하도록 합니다. 각 각의 row에 대해, 여러분은 Cursor의 get 메소드들 중 하나(getString() 또는 getLong() 같은 )을 호출함으로서 컬룸(Column)의 값을 읽을 수 있습니다. get 메소드들 각각을 사용할 때, 여러분은 반드시 여러분이 원하는 column의 인덱스(index) 위치를 전달해야만 합니다. 컬룸(Column)의 인덱스(index)는 getColumnIndex() 또는 getColumnIndexOrThrow()를 호출해서 얻어낼 수 있습니다. 예:

 cursor.moveToFirst();

long itemId = cursor.getLong(

    cursor.getColumnIndexOrThrow(FeedEntry._ID)

);



데이터베이스로부터 정보 삭제하기(Delete Information from a Database)

-----------------------------------------------------------

DB테이블로부터 row들을 삭제하기 위해서는, row를 식별할 수 있는 기준 selection(일종의 검색 조건)을 제공해야만 합니다. 데이터베이스 API는 SQL 인젝션(injection :SQL문의 취약성)을 방지하기 위해 기준 seletion 을 생성하는 것에 대한 메커니즘(mechanism)을 제공합니다. 이 메커니즘은 selection을 selection 절(clause)과 selection 인자들(arguments)로 특성을 분할합니다. selection 절은 형태를 보면 Column들을 정의하고 또한 Column 테스트와 결합할 수 있습니다. selection 인자들은seletion 절에 연결되어 테스트할(검색) 조건에 대응되는 값입니다. 그 결과는 정규 SQL 문과 같이 처리되지 않기 때문에 SQL 인젝션(injection)에 대해 영향을 받지 않습니다.


 // Define 'where' part of query.

String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";

// Specify arguments in placeholder order.

String[] selectionArgs = { String.valueOf(rowId) };

// Issue SQL statement.

db.delete(table_name, selection, selectionArgs);




데이터베이스 갱신하기( Update a Database)

------------------------------------

여러분이 데이터베이스의 값중 일부를 수정해야 하는 경우에는 Update() 메소드를 사용합니다.


DB테이블을 업데이트 하는 것은 insert()의 컨텐츠 값(contents value)구문과 delete()의 where구문을 결합한 것입니다.

 SQLiteDatabase db = mDbHelper.getReadableDatabase();


// New value for one column

ContentValues values = new ContentValues();

values.put(FeedEntry.COLUMN_NAME_TITLE, title);


// Which row to update, based on the ID

String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";

String[] selectionArgs = { String.valueOf(rowId) };


int count = db.update(

    FeedReaderDbHelper.FeedEntry.TABLE_NAME,

    values,

    selection,

    selectionArgs);


반응형

+ Recent posts