[Android] SQLite

 πŸ’‘ μš°μ•„ν•œν…Œν¬μ½”μŠ€ ν™œλ™ 쀑에 μ‚¬μš©ν•œ SQLite에 λŒ€ν•˜μ—¬ ν•™μŠ΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€ !

 

SQLite

  • SQLiteλŠ” λ°μ΄ν„°λ² μ΄μŠ€ 관리 μ‹œμŠ€ν…œμœΌλ‘œ μ„œλ²„κ°€ μ•„λ‹Œ μ‘μš© ν”„λ‘œκ·Έλž¨μ— λ„£μ–΄ μ‚¬μš©ν•˜λŠ” κ°€λ²Όμš΄ λ°μ΄ν„°λ² μ΄μŠ€μž…λ‹ˆλ‹€.
  • 둜컬 데이터λ₯Ό 관리해야 ν•˜λŠ” λ‹€μ–‘ν•œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ‚¬μš©λ˜λ©°, μ•„λž˜μ™€ 같은 μ˜ˆμ‹œμ— 주둜 ν™œμš©λ©λ‹ˆλ‹€ !
    • μ‚¬μš©μž μ„€μ • 정보
    • 즐겨찾기
    • μΊμ‹œ 데이터
    • μ‚¬μš©μžμ˜ μ˜€ν”„λΌμΈ 생성 데이터
  • μ•ˆλ“œλ‘œμ΄λ“œμ— λ‚΄μž₯λ˜μ–΄ 있으며, μ–΄ν”Œμ΄ μ’…λ£Œλ˜κ±°λ‚˜ λ””λ°”μ΄μŠ€ 전원이 꺼지더라도 μ‚­μ œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

DBConstant

  • SQLite λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μ‚¬μš©ν•  λ•Œ, λ°μ΄ν„°λ² μ΄μŠ€ κ΄€λ ¨ μƒμˆ˜λ“€μ„ μ •μ˜ν•˜λŠ” 역할을 ν•˜λŠ” Constantμž…λ‹ˆλ‹€.
  • μ£Όμš” μ½”λ“œμ˜ 가독성을 높이고, μ‹€μˆ˜λ₯Ό λ°©μ§€ν•˜λ©΄μ„œ μ‰½κ²Œ μ°Έμ‘°ν•  수 μžˆλ„λ‘ ν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•©λ‹ˆλ‹€.
  • μ•„λž˜λŠ” μš°μ•„ν•œν…Œν¬μ½”μŠ€ ν™œλ™ 쀑에 μ„ μ–Έν•œ 였λͺ© λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μœ„ν•œ Constant μž…λ‹ˆλ‹€.
object OmockDBConstant {
    const val X_COORDINATE = "x_column"
    const val Y_COORDINATE = "y_row"
    const val TABLE_NAME = "omok_coordinates"
}
  • 각 였λͺ©μ— λŒ€ν•œ x,y μ’Œν‘œλ₯Ό μ €μž₯ν•˜κΈ° μœ„ν•œ μƒμˆ˜μ™€ ν…Œμ΄λΈ” 생성을 μœ„ν•œ ν…Œμ΄λΈ” λͺ…을 μ„ μ–Έν•˜μ˜€μŠ΅λ‹ˆλ‹€.

SQLiteOpenHelper

  • SQLiteOpenHelperλ₯Ό μƒμ†ν•˜μ—¬ λ°μ΄ν„°λ² μ΄μŠ€ 생성, μ—…κ·Έλ ˆμ΄λ“œ 및 관리λ₯Ό μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ•„λž˜ 두 가지 λ©”μ„œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ“œ ν•©λ‹ˆλ‹€.
    • onCreate() : λ°μ΄ν„°λ² μ΄μŠ€κ°€ 처음 생성 될 λ•Œ ν˜ΈμΆœλ©λ‹ˆλ‹€.
    • onUpgrade() : λ°μ΄ν„°λ² μ΄μŠ€ μŠ€ν‚€λ§ˆκ°€ 변경될 λ•Œ ν˜ΈμΆœλ©λ‹ˆλ‹€.
class DBHelper(context: Context) :
    SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {

    override fun onCreate(db: SQLiteDatabase?) {
        val createTableQuery =
            "CREATE TABLE omok_coordinates (" +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
                "${OmockDBConstant.X_COORDINATE} INTEGER," +
                "${OmockDBConstant.Y_COORDINATE} INTEGER" +
                ");"
        db?.execSQL(createTableQuery)
    }

    override fun onUpgrade(
        db: SQLiteDatabase?,
        oldVersion: Int,
        newVersion: Int,
    ) {
        db?.execSQL("DROP TABLE IF EXISTS omok_coordinates")
        onCreate(db)
    }

    companion object {
        private const val DATABASE_NAME = "omok.db"
        private const val DATABASE_VERSION = 4
    }
}
  • onCreate() μ‹œμ— ν…Œμ΄λΈ” 쿼리λ₯Ό μƒμ„±ν•˜κ³ , execSQL을 ν™œμš©ν•˜μ—¬ SQL 쿼리λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.
    • ν…Œμ΄λΈ” 쿼리 생성 μ‹œ 고유 id(PRIMARY KEY)와 μƒμˆ˜λ‘œ μ„ μ–Έν•œ x,y μ’Œν‘œλ₯Ό Int κ°’μœΌλ‘œ μ„ μ–Έν•˜μ˜€μŠ΅λ‹ˆλ‹€.

DAO

  • DAOλž€ Data Access Object의 μ•½μžλ‘œ λ°μ΄ν„°λ² μ΄μŠ€μ˜ data에 μ ‘κ·Όν•˜κΈ° μœ„ν•œ κ°μ²΄μž…λ‹ˆλ‹€.
  • DB에 μ ‘κ·Όν•˜κΈ° μœ„ν•œ λ‘œμ§μ„ λΆ„λ¦¬ν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
  • DAO에 총 3가지 λ©”μ„œλ“œλ₯Ό μ„ μ–Έν•˜μ˜€μŠ΅λ‹ˆλ‹€.
  • 쿼리에 λŒ€ν•œ μ ‘κ·Όλ§Œ ν—ˆμš©ν•˜λŠ” 경우 DBλ₯Ό readableDatabase둜 μƒμ„±ν•©λ‹ˆλ‹€.
  • 쿼리에 λŒ€ν•œ μˆ˜μ •, μ‚­μ œ, μΆ”κ°€κ°€ μ΄λ£¨μ–΄μ§€λŠ” 경우 writableDatabase둜 μƒμ„±ν•©λ‹ˆλ‹€.
class OmokDAO(context: Context) {
    private val dbHelper = DBHelper(context)
	
		....
		
		companion object {
        private const val DATABASE_NAME = "omok.db"
        private const val DATABASE_VERSION = 4
    }
}

Insert

  • insertCoordinate(x,y) : x,y μ’Œν‘œλ₯Ό λ°›μ•„μ„œ db에 μ €μž₯ν•˜λŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€.
fun insertCoordinate(
    x: Int,
    y: Int,
) {
    val db = dbHelper.writableDatabase
    val values =
        ContentValues().apply {
            put(OmockDBConstant.X_COORDINATE, x)
            put(OmockDBConstant.Y_COORDINATE, y)
        }
    db.insert(OmockDBConstant.TABLE_NAME, null, values)
    db.close()
}

Select

  • getAllCoordinates() : DB에 μ €μž₯ 된 λͺ¨λ“  x,y μ’Œν‘œλ₯Ό λΆˆλŸ¬μ˜€λŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€.
    • μ»€μ„œλ₯Ό μ‚¬μš©ν•˜μ—¬ λͺ¨λ“  데이터λ₯Ό μ½μ–΄μ˜¬ λ•ŒκΉŒμ§€ λ°˜λ³΅ν•©λ‹ˆλ‹€.
fun getAllCoordinates(): List<Pair<Int, Int>> {
    val db = dbHelper.readableDatabase
    val cursor: Cursor =
        db.rawQuery(
            "SELECT ${OmockDBConstant.X_COORDINATE},${OmockDBConstant.Y_COORDINATE} FROM omok_coordinates",
            null,
        )
    val coordinates = mutableListOf<Pair<Int, Int>>()
    with(cursor) {
        while (moveToNext()) {
            val column = getInt(getColumnIndexOrThrow(OmockDBConstant.X_COORDINATE))
            val row = getInt(getColumnIndexOrThrow(OmockDBConstant.Y_COORDINATE))
            coordinates.add(Pair(column, row))
        }
    }
    cursor.close()
    db.close()
    return coordinates
}

Delete

  • resetAllCoordinates() : λͺ¨λ“  μ’Œν‘œλ₯Ό μ œκ±°ν•˜λŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€.
fun resetAllCoordinates() {
    val db = dbHelper.writableDatabase
    db.delete(OmockDBConstant.TABLE_NAME, null, null)
    db.close()
}

Activityμ—μ„œ DAO μ ‘κ·Ό

  • 이제 μž‘μ„±ν•œ DAOλ₯Ό μ•‘ν‹°λΉ„ν‹°μ—μ„œ μƒμ„±ν•΄μ„œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
private val dao = OmokDAO(this@MainActivity)
  • μœ„μ²˜λŸΌ μ„ μ–Έν•˜μ—¬ μ‚¬μš©ν•  수 있으며, DAO에 μƒμ„±ν•œ 쿼리λ₯Ό μ‹€ν–‰ν•˜λŠ” ν•¨μˆ˜λ‘œ κ°„λ‹¨ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
//insert
dao.insertCoordinate(columIndex, rowIndex)
//select
dao.getAllCoordinates().forEach { (columnIndex, rowIndex) -> }
//delete
dao.resetAllCoordinates()

정리

  • SQLiteλŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ‚΄μ—μ„œ μ„œλ²„μ™€ μ—°κ²° 없이 데이터λ₯Ό λ‘œμ»¬μ— 영ꡬ μ €μž₯ν•΄μ•Ό ν•˜λŠ” 경우 μœ μš©ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • κ²½λŸ‰ν˜• λ°μ΄ν„°λ² μ΄μŠ€ 관리 μ‹œμŠ€ν…œμœΌλ‘œ κ°„νŽΈν•˜κ²Œ μ‚¬μš©ν•  수 μžˆλ‹€λŠ” μž₯점이 μžˆμŠ΅λ‹ˆλ‹€.
  • λ‹¨μ μœΌλ‘œλŠ” λ™μ‹œμ„± 보μž₯κ³Ό λŒ€κ·œλͺ¨ 데이터 μ²˜λ¦¬μ— λΆ€μ ν•©ν•˜λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.
    • λ™μ‹œμ— μ“°κΈ° μž‘μ—…μ„ μ²˜λ¦¬ν•˜λŠ” 데 μ œμ•½μ΄ 있음
    • λ‹€μˆ˜μ˜ μ“°κΈ° μž‘μ—…μ„ ν†΅ν•œ μ„±λŠ₯ μ €ν•˜κ°€ 있음
    • λŒ€κ·œλͺ¨ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—λŠ” νš¨μœ¨μ μ΄μ§€ μ•ŠμŒ