Android - SQLite 사용하기

Android 2016.01.12 23:44 posted by TechNote.kr



Android 에서 Data를 저장하는 방식에 어려가지가 있다. 사실 PC라고 해서 딱히 다르지는 않다.

file system에 file 로 저장하는 방법, Database에 저장하는 방법, Network Storage에 저장하는 방법 등 여러가지가 있다. 


그 중 이 글에서는 database에 저장하는 방법에 대해 알아보고자 한다.


database에 대해 기본적인 지식이 있는 사람들은 알고 있겠지만 Database의 종류에도 여러가지가 있다. 

oracle, mysql, mssql 등등등등.... 종류가 너무나도 많다.


그 중 android에 기본적으로 들어 있는 sqlite를 android app에서 접근해서 사용하는 방법에 대해 알아보자.


sqlite는 기본적으로 android에 들어 있고, 우리가 흔히 사용하는 android의 setting등 기본 설정값들을 저장하는 역할을 하기도 한다. 그렇다면 code상에서 sqlite에 access하려면 어떻게 해야 할까.


SQLiteOpenHelper Class 의 구현


class 이름에서 보듯이 sqlite를 open하기위한 helper class이다.

이 class를 상속해서 기본적인 api 2개만 구현해주면 사용이 가능하다.


하나는 이 class를 통해 사용할 db 를 생성하는 api.

다른 하나는 db version을 관리하게 하는 api.


    @Override

    public void onCreate(SQLiteDatabase db) {

        String sql = "create table memo (" +

                "_id integer primary key autoincrement, " +

                "title text, " +

                "body text, " +

                "done integer);";


        db.execSQL(sql);

    }

[db에 생성하려고하는 db name이 없을 경우 db를 create한다.]


    @Override

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

        String sql = "drop table if exists student";

        db.execSQL(sql);


        onCreate(db);

    }

[이 부분은 version관리하는 api인데 사실 구현하기 나름인 부분으로 위에서는 단순히 기존 db를 drop하고 새로 다시 생성하는 코드를 넣어 놓았다.]


기본적으로 위와 같이 2개의 api만 만들어주면 기본적인 동작을 하는데 문제가 없다.

하지만 나같은 경우에는 help해 주는 김에 SQL의 CRUD(create, read, update, delete)를 좀 더 도와줄수 있게 추가해 보았다.


INSERT


    public void insert(String title, String body, int done) {

        db = this.getWritableDatabase();


        ContentValues values = new ContentValues();

        values.put("title", title);

        values.put("body", body);

        values.put("done", done);

        db.insert("memo", null, values);

        this.close();

    }

DB를 Writable하게 access해서 insert후 열었던 DB를 close하는 코드



UPDATE


    public void update(int _id, String title, String body, int done) {

        db = this.getWritableDatabase();


        ContentValues values = new ContentValues();

        values.put("title", title);

        values.put("body", body);

        values.put("done", done);

        db.update("memo", values, "_id=?", new String[]{String.valueOf(_id)});


        this.close();

    }

INSERT때와 마찬가지고 getWritableDatabase()를 통해 Write가능하게 open 한뒤 update후 열었던 DB를 close하는 코드. 하기 나름이겠지만 여기서는 primary key인 _id를 기준으로 update하도록 하였다.



DELETE


    public void delete(int _id) {

        db = this.getWritableDatabase();

        db.delete("memo","_id=?", new String[]{String.valueOf(_id)});

        this.close();

    }

delete를 하는 부분으로 마찬가지로 write가능하게 open해야 한다. primary key 인 _id 값 기준으로 delete하도록 구현하였다.



SELECT


    public void select() {

        db = this.getReadableDatabase();

        Cursor c = db.query("memo", null, null, null, null, null, null);

        while(c.moveToNext()) {

            int _id = c.getInt(c.getColumnIndex("_id"));

            String title = c.getString(c.getColumnIndex("title"));

            String body = c.getString(c.getColumnIndex("body"));

            int done = c.getInt(c.getColumnIndex("done"));


            Log.e("db", "id: " + _id + " : " + _id + " : " + title + " : " + body + " : " + done);

        }

        this.close();

    }

select는 아시다시피 read operation이므로 getWritableDatabase()를 사용하지 않고, getReadableDatabase()를 사용한다. 이렇게 open 한 DB에 query를 날리고 결과물은 Cursor Instance에 담게 된다. 여기서 Cursor는 마우스 cursor도 아니고, 단어가 좀 바로 이해가 안가는 부분이 있어서 좀 찾아 보았다.


Cursor Class는 다음과 같이 정의되어 있었다. 

This interface provides random read-write access to the result set returned by a database query.

즉, database query의 결과물을 저장하는 것.

이렇게 위에 구현된 select는 cursor instance에 DB query 저장한 결과물을 넣고, 그 결과물을 Log로 출력하게 구현하였다.


이렇게 기본 API인 onCreate, onUpgrade 를 구현하고, 부차적으로 나름 필요한 INSERT, SELECT, UPDATE, DELETE를 구현한 SQLiteOpenHelper Class를 다음과 같이 사용하면 된다.



 getWritableDatabase 와 getReadableDatabase.


 위 코드를 보면 INSERT, UPDATE, DELETE 에서는 getWritableDatabase, SELECT에서는 getReadableDatabase를 사용하고 있다. 여기서 하나 의문이 드는 점이 있어 찾아본게 있는데, 어짜피 getWritableDatabase에서도 read가 된다면 굳이 구분해가면서 getReadableDatabase를 사용해야 하냐는 것이었다. 찾아본 결과 getReadableDatabase를 사용하게 되면 성능에 이득이 있다고 한다. 잘 구분해서 써야 겠다.



SQLiteOpenHelper Class의 사용


        helper = new TestSQLiteOpenHelper(MainActivity.this, "Test.db", null, 1);


        helper.update(1, "12345", "ABCDEFG", 0);

        helper.select();

        helper.update(1, "ABCDE", "1234567", 1);

        helper.select();


위와 같이 구현한 코드의 출력물을 보면 다음과 같다.


01-12 21:06:35.211 E/db: id: 1 : 1 : 12345 : ABCDEFG : 0

01-12 21:06:35.231 E/db: id: 1 : 1 : ABCDE : 1234567 : 1