안드로이드 Room 데이터베이스 활용하기 🚀

콘텐츠 대표 이미지 - 안드로이드 Room 데이터베이스 활용하기 🚀

 

 

안녕하세요, 개발자 여러분! 오늘은 안드로이드 앱 개발의 핵심 요소 중 하나인 Room 데이터베이스에 대해 알아볼 거예요. 😎 Room은 SQLite 데이터베이스를 더 쉽고 효율적으로 사용할 수 있게 해주는 강력한 도구인데요, 이걸 제대로 활용하면 여러분의 앱 개발 실력이 한 단계 업그레이드될 거예요! ㅋㅋㅋ

💡 Tip: Room을 마스터하면 데이터 관리가 훨씬 수월해져요. 마치 재능넷에서 다양한 재능을 쉽게 찾고 관리하는 것처럼요!

Room이 뭐길래? 🤔

Room은 구글이 만든 ORM(Object-Relational Mapping) 라이브러리예요. 쉽게 말해서, 복잡한 SQL 쿼리 대신 자바 객체를 사용해 데이터베이스를 다룰 수 있게 해주는 도구라고 보면 돼요. 완전 개발자 친화적이죠? 👍

Room을 사용하면 데이터베이스 작업이 훨씬 간단해지고, 코드도 깔끔해져요. 마치 재능넷에서 원하는 재능을 쉽게 찾는 것처럼 말이죠!

Room의 주요 구성요소

  • Entity: 데이터베이스 테이블을 나타내는 클래스
  • DAO (Data Access Object): 데이터베이스 작업을 정의하는 인터페이스
  • Database: 데이터베이스 인스턴스를 관리하는 클래스

이 세 가지만 잘 이해하면 Room 마스터가 될 수 있어요! 😉

Room 시작하기 🚀

자, 이제 본격적으로 Room을 사용해볼까요? 먼저 프로젝트에 Room 의존성을 추가해야 해요.


dependencies {
    def room_version = "2.4.3"
    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version"
}

이렇게 의존성을 추가하면 Room을 사용할 준비 완료! 👌

Entity 만들기

이제 데이터베이스 테이블을 나타내는 Entity 클래스를 만들어볼게요. 예를 들어, 사용자 정보를 저장하는 테이블을 만든다고 해볼까요?


@Entity(tableName = "users")
public class User {
    @PrimaryKey
    public int uid;

    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;

    // 생성자, getter, setter 등은 생략
}

와우! 이렇게 간단한 클래스로 데이터베이스 테이블을 정의할 수 있다니, 완전 쉽죠? 😆

DAO 인터페이스 만들기

다음은 DAO 인터페이스를 만들어볼게요. 여기서 데이터베이스 작업을 정의할 거예요.


@Dao
public interface UserDao {
    @Query("SELECT * FROM users")
    List<user> getAll();

    @Query("SELECT * FROM users WHERE uid IN (:userIds)")
    List<user> loadAllByIds(int[] userIds);

    @Insert
    void insertAll(User... users);

    @Delete
    void delete(User user);
}
</user></user>

이렇게 DAO를 정의하면 복잡한 SQL 쿼리 없이도 데이터베이스 작업을 할 수 있어요. 완전 개발자 천국이죠? ㅋㅋㅋ

Database 클래스 만들기

마지막으로 Database 클래스를 만들어볼게요. 이 클래스는 실제 데이터베이스 인스턴스를 관리해요.


@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();

    private static volatile AppDatabase INSTANCE;

    static AppDatabase getDatabase(final Context context) {
        if (INSTANCE == null) {
            synchronized (AppDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            AppDatabase.class, "app_database")
                            .build();
                }
            }
        }
        return INSTANCE;
    }
}

이렇게 하면 Room 데이터베이스 설정 완료! 🎉

Room 사용하기 💪

자, 이제 Room을 실제로 사용해볼까요? 데이터를 저장하고 불러오는 방법을 알아볼게요.

데이터 저장하기


AppDatabase db = Room.databaseBuilder(getApplicationContext(),
        AppDatabase.class, "database-name").build();

User user = new User();
user.uid = 1;
user.firstName = "John";
user.lastName = "Doe";

db.userDao().insertAll(user);

이렇게 하면 새로운 사용자 정보가 데이터베이스에 저장돼요. 완전 쉽죠? 😎

데이터 불러오기


List<user> users = db.userDao().getAll();
for (User user : users) {
    Log.d("UserInfo", "Name: " + user.firstName + " " + user.lastName);
}
</user>

이렇게 간단하게 데이터를 불러올 수 있어요. 마치 재능넷에서 원하는 재능을 검색하는 것처럼 쉽죠?

Room의 장점 🌟

Room을 사용하면 정말 많은 이점이 있어요. 몇 가지 살펴볼까요?

  • 컴파일 타임 검사: SQL 쿼리의 오류를 컴파일 시점에 잡아낼 수 있어요.
  • 보일러플레이트 코드 감소: 반복적인 코드를 줄여줘요.
  • LiveData와의 통합: 데이터 변경을 실시간으로 관찰할 수 있어요.
  • RxJava 지원: 비동기 프로그래밍을 더 쉽게 할 수 있어요.

이런 장점들 때문에 Room은 안드로이드 개발자들 사이에서 엄청 인기 있어요. 마치 재능넷이 다양한 재능을 가진 사람들 사이에서 인기 있는 것처럼요! 😉

Room 고급 기능 🚀

Room의 기본적인 사용법을 알았으니, 이제 좀 더 고급 기능들을 살펴볼까요?

관계 설정하기

Room에서는 테이블 간의 관계도 쉽게 설정할 수 있어요. 예를 들어, 사용자와 그 사용자의 애완동물 정보를 연결해볼까요?


@Entity
public class Pet {
    @PrimaryKey
    public int petId;

    public String name;

    public int ownerId;  // User의 uid를 참조
}

@Dao
public interface UserWithPetsDao {
    @Query("SELECT * FROM User")
    List<userwithpets> getUsersWithPets();
}

public class UserWithPets {
    @Embedded
    public User user;

    @Relation(
        parentColumn = "uid",
        entityColumn = "ownerId"
    )
    public List<pet> pets;
}
</pet></userwithpets>

이렇게 하면 사용자와 애완동물 정보를 한 번에 가져올 수 있어요. 완전 편하죠? ㅋㅋㅋ

Type Converter 사용하기

Room은 기본적으로 primitive 타입과 String만 지원해요. 하지만 Type Converter를 사용하면 다른 타입도 저장할 수 있어요!


public class DateConverter {
    @TypeConverter
    public static Date fromTimestamp(Long value) {
        return value == null ? null : new Date(value);
    }

    @TypeConverter
    public static Long dateToTimestamp(Date date) {
        return date == null ? null : date.getTime();
    }
}

@Database(entities = {User.class}, version = 1)
@TypeConverters({DateConverter.class})
public abstract class AppDatabase extends RoomDatabase {
    // ...
}

이렇게 하면 Date 타입도 데이터베이스에 저장할 수 있어요. 완전 꿀팁이죠? 😋

Migration 처리하기

앱을 업데이트하다 보면 데이터베이스 구조를 변경해야 할 때가 있어요. 이럴 때 Migration을 사용하면 돼요!


static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("ALTER TABLE User ADD COLUMN age INTEGER");
    }
};

Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "database-name")
    .addMigrations(MIGRATION_1_2)
    .build();

이렇게 하면 데이터베이스 버전이 변경되어도 기존 데이터를 잃지 않고 업그레이드할 수 있어요. 완전 안전하죠? 👍

Room 성능 최적화 팁 🚀

Room을 사용할 때 성능을 더 높일 수 있는 팁들을 알아볼까요?

인덱스 사용하기

자주 검색하는 컬럼에는 인덱스를 추가하면 검색 속도가 빨라져요.


@Entity(indices = {@Index("name")})
public class User {
    @PrimaryKey
    public int uid;

    @ColumnInfo(name = "name")
    public String name;

    // ...
}

이렇게 하면 name 컬럼으로 검색할 때 속도가 빨라져요. 완전 스피드업! 🏎️

트랜잭션 사용하기

여러 작업을 한 번에 처리해야 할 때는 트랜잭션을 사용하면 좋아요.


@Dao
public interface UserDao {
    @Transaction
    @Query("SELECT * FROM User")
    List<userwithpets> getUsersWithPets();
}
</userwithpets>

이렇게 하면 여러 작업을 안전하고 효율적으로 처리할 수 있어요. 마치 재능넷에서 여러 재능을 한 번에 검색하는 것처럼요! 😉

비동기 처리하기

데이터베이스 작업은 메인 스레드에서 하면 안 돼요. RxJava나 Coroutines를 사용해서 비동기로 처리해야 해요.


@Dao
public interface UserDao {
    @Query("SELECT * FROM User")
    Flowable<list>> getAllUsers();
}

// 사용 예
userDao.getAllUsers()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(users -> {
        // UI 업데이트
    });
</list>

이렇게 하면 앱이 훨씬 더 부드럽게 동작해요. 완전 실크 터치! 👌

Room 테스팅 🧪

Room을 사용할 때 테스트 코드를 작성하는 것도 중요해요. 어떻게 하는지 알아볼까요?

In-Memory 데이터베이스 사용하기

테스트할 때는 실제 데이터베이스 대신 메모리 내 데이터베이스를 사용하면 좋아요.


@RunWith(AndroidJUnit4.class)
public class UserDaoTest {
    private UserDao userDao;
    private AppDatabase db;

    @Before
    public void createDb() {
        Context context = ApplicationProvider.getApplicationContext();
        db = Room.inMemoryDatabaseBuilder(context, AppDatabase.class).build();
        userDao = db.userDao();
    }

    @After
    public void closeDb() {
        db.close();
    }

    @Test
    public void insertAndGetUser() {
        User user = new User();
        user.uid = 1;
        user.firstName = "John";
        user.lastName = "Doe";

        userDao.insert(user);

        List<user> users = userDao.getAll();
        assertEquals(1, users.size());
        assertEquals("John", users.get(0).firstName);
    }
}
</user>

이렇게 하면 실제 데이터에 영향을 주지 않고 테스트할 수 있어요. 완전 안전하고 깔끔하죠? 😎

Room 실전 프로젝트 예제 🚀

자, 이제 Room을 사용한 실전 프로젝트 예제를 살펴볼까요? 간단한 메모 앱을 만들어볼게요.

1. Entity 정의하기


@Entity(tableName = "memos")
public class Memo {
    @PrimaryKey(autoGenerate = true)
    public int id;

    @ColumnInfo(name = "title")
    public String title;

    @ColumnInfo(name = "content")
    public String content;

    @ColumnInfo(name = "created_at")
    public Date createdAt;
}

2. DAO 만들기


@Dao
public interface MemoDao {
    @Query("SELECT * FROM memos ORDER BY created_at DESC")
    List<memo> getAll();

    @Insert
    void insert(Memo memo);

    @Update
    void update(Memo memo);

    @Delete
    void delete(Memo memo);
}
</memo>

3. Database 클래스 만들기


@Database(entities = {Memo.class}, version = 1)
@TypeConverters({DateConverter.class})
public abstract class AppDatabase extends RoomDatabase {
    public abstract MemoDao memoDao();

    private static volatile AppDatabase INSTANCE;

    static AppDatabase getDatabase(final Context context) {
        if (INSTANCE == null) {
            synchronized (AppDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            AppDatabase.class, "memo_database")
                            .build();
                }
            }
        }
        return INSTANCE;
    }
}

4. ViewModel 만들기