본문 바로가기

Study/Android

Room Database 써 보기

Room 사용을 위한 3가지 중요한 요소

  • Database :  데이터베이스 홀더를 포함하고, 관계형 데이터 베이스에 접근할 수 있는 액세스 포인트를 제공한다.
    @Database라는 애노테이션을 클래스에 달아야 하며,  다음과 같은 조건을 만족해야한다.
    • RoomDatabase를 상속해야한 abstract class여야 한다.
    • 데이터베이스와 관련된 엔티티들을 애노테이션의 인자값으로 포함해야한다.
    • abstract method 포함해야하는데, 이 메소드에는 인자가 0개이고 return 되는클래스가 @Dao 애노테이션을 달고 있어야한다.

    런타임때에는 Room.databaseBuilder() 또는 Room.inMemoryDatabaseBuilder()를 통해 Database의 객체를 얻어 낼 수 있다.

  • Entity : 데이터베이스의 테이블을 표현한다
  • DAO : 데이터베이스에 접속하기 위한 메소드를 포함한다.

 

Database

MemoryDatabase.java

package com.sample;

import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.room.Database;
import android.arch.persistence.room.Room;
import android.arch.persistence.room.RoomDatabase;
import android.arch.persistence.room.migration.Migration;
import android.content.Context;
import android.database.Cursor;
import android.support.annotation.NonNull;

import timber.log.Timber;

@Database(entities =
        {
                Memory.class
        }, version = 2) //version은 database가 업데이트 될 때마다 1씩 추가된다.
public class MemoryDatabase extends RoomDatabase {
    private static final String DATABASE_NAME = "memory-db.db";

    public abstract MemoryDao memoryDao();

    private static MemoryDatabase sInstance;
    private static Context mContext;

    synchronized public static MemoryDatabase getInstance(final Context context) {
        if (sInstance == null) {
            sInstance = buildDatabase(context.getApplicationContext());
        }
        mContext = context.getApplicationContext();
        return sInstance;
    }

    private static MemoryDatabase buildDatabase(Context applicationContext) {
        return Room.databaseBuilder(applicationContext, MemoryDatabase.class, DATABASE_NAME).addCallback(new RoomDatabase.Callback() {
            @Override
            public void onCreate(@NonNull SupportSQLiteDatabase db) {
                Timber.d("create database schema ver.%d", db.getVersion());

                super.onCreate(db);
            }
        }).addMigrations(MIGRATION_1_2)
                .addMigrations(MIGRATION_2_3)
                .build();
    }

    private static Migration MIGRATION_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            Timber.d("db migrate: from 1 to 2");

            // create
            database.execSQL("CREATE TABLE memory (memory_id TEXT NOT NULL PRIMARY KEY)");

            // add column, update
            database.execSQL("ALTER TABLE memory ADD COLUMN memory_content TEXT");
            database.execSQL("UPDATE memory SET memory_content = content");

            // 컬럼 여부 묻고 컬럼 삭제
            if (columnExist(database, "memory", "memory_content")) {
                database.execSQL("CREATE TABLE memory_backup (memory_id TEXT NOT NULL PRIMARY KEY)");
                database.execSQL("INSERT INTO memory_backup SELECT memory_id FROM memory");
                database.execSQL("DROP TABLE memory");
                database.execSQL("ALTER TABLE memory_backup RENAME TO memory");
            }

            // 컬럼 여부 묻고 컬럼 추가
            if (!columnExist(database, "memory", "memory_content")) {
                database.execSQL("ALTER TABLE memory ADD COLUMN memory_content TEXT");
            }

        }
    };

    private static Migration MIGRATION_2_3 = new Migration(2, 3) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            Timber.d("db migrate: from 2 to 3");

            //
            database.execSQL("CREATE TABLE memory (memory_id TEXT NOT NULL PRIMARY KEY)");
        }
    };

    private static boolean columnExist(SupportSQLiteDatabase database, String table, String column) {
        try (Cursor cursor = database.query("PRAGMA table_info(" + table + ")", null)) {
            while (cursor != null && cursor.moveToNext()) {
                String name = cursor.getString(cursor.getColumnIndex("name"));
                if (column.equalsIgnoreCase(name)) {
                    return true;
                }
            }
        }
        return false;
    }

    public void clearDatabase() {
        sInstance.memoryDao().deleteAll();
    }
}

 

Entity

Memory.java

package com.sample;

import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.PrimaryKey;
import android.support.annotation.NonNull;

@Entity(tableName = "memory")
public class Memory {
    @PrimaryKey
    @NonNull
    @ColumnInfo(name = "memory_id")
    public String memoryId;

    public Memory(String memoryId) {
        this.memoryId = memoryId;
    }
}

 

DAO

MemoryDao.java

package com.sample;

import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Query;

import com.lgeha.nuts.database.dao.BaseDao;

@Dao
public abstract class MemoryDao implements BaseDao<Memory> {
    @Query("SELECT memory_id FROM memory LIMIT 1")
    public abstract String getMemoryId();

    @Query("SELECT COUNT(*) FROM memory")
    public abstract int counts();

    @Query("UPDATE memory SET memory_id = :memory_id")
    public abstract void updateMemoryId(String memory_id);

    @Query("DELETE FROM memory")
    public abstract void deleteAll();
}