[Android] SQLite

leeehaยท2022๋…„ 11์›” 5์ผ
0
post-thumbnail

๋ฐ์ดํ„ฐ ์ €์žฅ ๋ฐฉ๋ฒ•

  • File Read/Write โ†’ ์ด๋ฏธ์ง€ ํŒŒ์ผ์— ์ ํ•ฉ
  • SharedPreferences โ†’ ๋ฌธ์ž์—ด, ์ˆซ์ž, Boolean ๊ฐ’ ๋“ฑ์„ ์ €์žฅํ•˜๋Š” ์„ค์ • ํŒŒ์ผ์— ์ ํ•ฉ, ๊ทธ๋Ÿฌ๋‚˜ key-value ํ˜•ํƒœ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋ฏ€๋กœ ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ์—๋Š” ๋ถ€์ ํ•ฉํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์กฐํ™” ์‹œํ‚ค๊ธฐ๋„ ์–ด๋ ค์›€.
  • Database โ†’ row์™€ colum์„ ๊ฐ–๋Š” ํ…Œ์ด๋ธ” ํ˜•ํƒœ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์กฐํ™” ์‹œ์ผœ์„œ ์ €์žฅํ•จ.

SQLite

  • ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ์˜ ๋กœ์ปฌ DB (์„œ๋ฒ„์‚ฌ์ด๋“œ X)
  • ์„œ๋ฒ„์‚ฌ์ด๋“œ์˜ DB์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ์ปฌ์— ์ €์žฅํ•˜์—ฌ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•จ. (๋ฐ์ดํ„ฐ ์บ์‹ฑ)
  • SQLite๋Š” ์˜คํ”ˆ์†Œ์Šค๋กœ ๋งŒ๋“ค์–ด์ง„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ, ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ํ•ด๋‹นํ•จ.
  • ๋ณต์žกํ•˜๊ณ  ๊ตฌ์กฐํ™”๋œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•จ.
  • SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ๋ณ„๋„๋กœ ์‹คํ–‰๋˜๋Š” ํ”„๋กœ์„ธ์Šค๊ฐ€ ์•„๋‹ˆ๋ผ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํ•ด๋‹นํ•จ.
  • ๋”ฐ๋ผ์„œ, ์ƒ์„ฑํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ผ๋ถ€๋กœ ํ†ตํ•ฉ๋จ.
  • SQLite๋ฅผ ์ด์šฉํ•œ ๋ฐ์ดํ„ฐ๋Š” ๋‚ด์žฅ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์ธ /data/data/<package_name/>/databases ํด๋”์— ํŒŒ์ผ๋กœ ์ €์žฅ๋จ. (๋‹ค๋ฅธ ์•ฑ๊ณผ ๊ณต์œ  ๋ถˆ๊ฐ€)

SQLiteOpenHelper

  • SQLiteDatabase ๊ฐ์ฒด ์ด์šฉ์€ ํ•„์ˆ˜
  • SQLiteOpenHelper ํด๋ž˜์Šค๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ฆฌ ์ฝ”๋“œ๋ฅผ ์ถ”์ƒํ™” ์‹œํ‚ค๋Š” ์—ญํ• 
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒ์˜ ํ…Œ์ด๋ธ” create(์ƒ์„ฑ), alter(๋ณ€๊ฒฝ), drop(์‚ญ์ œ) ๋“ฑ์„ ์œ„ํ•œ ์ฝ”๋“œ

SQLiteOpenHelper ํด๋ž˜์Šค ์ƒ์†

// ๋งˆ์ง€๋ง‰ ์ธ์ž๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฒ„์ „ ์ •๋ณด 
class DBHelper(context: Context): SQLiteOpenHelper(context, "testdb", null, 1) {
	// ... 
}

๋ฉ”์†Œ๋“œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ

  • onCreate(): ์•ฑ์ด ์„ค์น˜๋œ ํ›„์— ์ตœ์ดˆ๋กœ SQLiteOpenHelper ํด๋ž˜์Šค๊ฐ€ ์ด์šฉ๋˜๋Š” ์ˆœ๊ฐ„์— ํ•œ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋จ. (๋ณดํ†ต ํ…Œ์ด๋ธ” ์ƒ์„ฑ ์‹œ)
  • onUpgrade(): SQLiteOpenHelper ์ƒ์„ฑ์ž์˜ ๋งˆ์ง€๋ง‰ ์ธ์ž์— ์ง€์ •ํ•œ DB ๋ฒ„์ „ ์ •๋ณด๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋จ. (๋ณดํ†ต ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ ์‹œ)

SQLiteDatabase ๊ฐ์ฒด ํš๋“

  • SQLiteOpenHelper์˜ readableDatabase, writableDatabase ์†์„ฑ์œผ๋กœ SQLiteDatabase ๊ฐ์ฒด ํš๋“
val db: SQLiteDatabase = DBHelper(this).writableDatabase 

์‹ค์Šต ์˜ˆ์ œ

DBHelper ํด๋ž˜์Šค ์ƒ์„ฑ

package com.tutorial.c59

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

class DBHelper(context: Context): SQLiteOpenHelper(context, "testdb", null, 1) {
    override fun onCreate(db: SQLiteDatabase?) {
        val studentSql = """
           create table tb_member(
           _id integer primary key autoincrement,
           name not null,
           email, 
           phone)
        """
        db?.execSQL(studentSql)
        db?.execSQL("insert into tb_member (name, email, phone) " +
                "values ('haeun', 'jxlhe46@gmail.com', '01012345678')")
    }

    override fun onUpgrade(db: SQLiteDatabase?, p1: Int, p2: Int) {
        // Drop the older tables
        db?.execSQL("drop table tb_member")
        
        // Create table again
        onCreate(db)
    }
}

MainActivity

package com.tutorial.c59

import android.database.sqlite.SQLiteDatabase
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            val db: SQLiteDatabase = DBHelper(this).readableDatabase
            val cursor = db.rawQuery("select name from tb_member", null)
            if(cursor.moveToFirst()){
                Toast.makeText(this, cursor.getString(0), Toast.LENGTH_SHORT).show()
            }
            db.close()
        }
    }
}

์‹คํ–‰ ๊ฒฐ๊ณผ


execSQL, rawQuery

SQLiteDatabase

  • SQLite๋ฅผ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ตœ์†Œํ•œ์˜ API
  • SQLiteOpenHelper ๊ฐ์ฒด์˜ ์†์„ฑ ๋˜๋Š” openOrCreateDatabase() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ํš๋“
val db = openOrCreateDatabase("testdb", Context.MODE_PRIVATE, null)

execSQL

public void execSQL(String sql, Object[] bindArgs)

db.execSQL("create table USER_TB(" + 
		"_id integer primary key autoincrement," + 
        "name not null," + 
        "phone") 

db.execSQL("insert into USER_TB (name, phone) values (?,?)", arrayOf("kkang", "01012345678"))

rawQuery

public Cursor rawQuery(String sql, String[] selectionArgs)

val cursor = db.rawQuery("select * from USER_TB", null) 
  • rawQuery() ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด๊ฐ’์€ Cursor ๊ฐ์ฒด์ด๋ฉฐ select๋œ row๋ฅผ ๊ฐ€๋ฆฌํ‚ด.
  • Cursor ๊ฐ์ฒด๋ฅผ ์›€์ง์—ฌ์„œ row๋ฅผ ์„ ํƒํ•˜๊ณ , ์„ ํƒ๋œ row์˜ column ๋ฐ์ดํ„ฐ๋ฅผ ํš๋“ํ•จ.

while(cursor.moveToNext()){ // ๋‹ค์Œ ํ–‰์œผ๋กœ ์ด๋™ 
	val name = cursor.getString(0) // ์—ด์˜ ์ธ๋ฑ์Šค ์ง€์ • 
    val phone = cursor.getString(1) 
}

์‹ค์Šต ์˜ˆ์ œ

์‹คํ–‰ ๊ฒฐ๊ณผ

DBHelper ํด๋ž˜์Šค ์ƒ์„ฑ

package com.tutorial.c60

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

class DBHelper(context: Context): SQLiteOpenHelper(context, "memodb", null, 1) {
    override fun onCreate(db: SQLiteDatabase?) {
        val memoSQL = """
            create table tb_memo(
            _id integer primary key autoincrement,
            title,
            content)
        """

        db?.execSQL(memoSQL)
    }

    override fun onUpgrade(p0: SQLiteDatabase?, p1: Int, p2: Int) {
        TODO("Not yet implemented")
    }
}

MainActivity

package com.tutorial.c60

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val titleView = findViewById<EditText>(R.id.add_title)
        val contentView = findViewById<EditText>(R.id.add_content)
        val addBtn = findViewById<Button>(R.id.add_btn)

        addBtn.setOnClickListener {
            val title = titleView.text.toString()
            val content = contentView.text.toString()

            val db = DBHelper(this).writableDatabase
            db.execSQL("insert into tb_memo (title, content) values (?, ?)",
                arrayOf(title, content))
            db.close()

            val intent = Intent(this, ReadActivity::class.java)
            startActivity(intent)
        }
    }
}

ReadActivity

package com.tutorial.c60

import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class ReadActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_detail)

        val titleView = findViewById<TextView>(R.id.read_title)
        val contentView = findViewById<TextView>(R.id.read_content)

        val db = DBHelper(this).readableDatabase

        // ์ตœ์‹  ์ž…๋ ฅ ๋ฐ์ดํ„ฐ 1๊ฑด์„ ์–ป์–ด์„œ ํ…์ŠคํŠธ๋ทฐ์— ์ถœ๋ ฅํ•˜๊ธฐ
        val cursor = db.rawQuery("select title, content from tb_memo " +
                "order by _id desc limit 1", null)
        while(cursor.moveToNext()){
            titleView.text = cursor.getString(0)
            contentView.text = cursor.getString(1)
        }
        db.close()
    }
}

insert, update, delete, query

  • insert(), update(), delete(), query() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ SQL๋ฌธ ์‹คํ–‰
  • SQL๋ฌธ์— ๋“ค์–ด๊ฐˆ ๋‚ด์šฉ์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋Œ€์ž…ํ•˜๋ฉด ํ•ด๋‹น SQL๋ฌธ์„ ๋งŒ๋“ค์–ด์„œ ์‹คํ–‰์‹œ์ผœ์ฃผ๋Š” ํ•จ์ˆ˜

  • ContentValues๋Š” insert, update๋ฅผ ์œ„ํ•œ ์นผ๋Ÿผ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ์•„๋†“์€ ๊ฐ์ฒด
  • Map ๊ฐ์ฒด์ฒ˜๋Ÿผ key-value ํ˜•ํƒœ๋กœ ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ๋ฅผ ContentValues์— ๋“ฑ๋ก
val values = ContentValues()
values.put("name", "kkang") 
values.put("phone", "01012345678") 
db.insert("USER_TB", null, values) // ์นผ๋Ÿผ ๋ฐ์ดํ„ฐ ์‚ฝ์ž… 

query()

  • table: select ํ•˜๋ ค๊ณ  ํ•˜๋Š” ํ…Œ์ด๋ธ”๋ช…
  • columns: ํš๋“ํ•˜๊ณ ์ž ํ•˜๋Š” column๋ช…, ๋ฐฐ์—ด ๋ฐ์ดํ„ฐ๋กœ column๋ช… ์ง€์ •
  • selection: select๋ฌธ์˜ where ๋’ค์— ๋“ค์–ด๊ฐˆ ๋ฌธ์ž์—ด
  • selectionArgs: selection์— ์ง€์ •๋œ ๋ฌธ์ž์—ด์ด ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐˆ ์ž๋ฆฌ๋ฅผ ?๋กœ ํ‘œํ˜„ํ–ˆ๋‹ค๋ฉด, ?์— ๋“ค์–ด๊ฐˆ ๋ฐ์ดํ„ฐ
  • groupBy: select๋ฌธ์˜ group by ๋’ค์— ๋“ค์–ด๊ฐˆ ๋ฌธ์ž์—ด
  • having: select๋ฌธ์˜ having ์กฐ๊ฑด
  • orderBy: select๋ฌธ์˜ order by ์กฐ๊ฑด

์‹ค์Šต ์˜ˆ์ œ

MainActivity

execSQL() ๋Œ€์‹  insert() ์‚ฌ์šฉํ•˜๊ธฐ

package com.tutorial.c60

import android.content.ContentValues
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val titleView = findViewById<EditText>(R.id.add_title)
        val contentView = findViewById<EditText>(R.id.add_content)
        val addBtn = findViewById<Button>(R.id.add_btn)

        addBtn.setOnClickListener {
            val title = titleView.text.toString()
            val content = contentView.text.toString()
            val db = DBHelper(this).writableDatabase

//            db.execSQL("insert into tb_memo (title, content) values (?, ?)",
//                arrayOf(title, content))
            
            val values = ContentValues()
            values.put("title", title)
            values.put("content", content)
            db.insert("tb_memo", null, values)
            db.close()

            val intent = Intent(this, ReadActivity::class.java)
            startActivity(intent)
        }
    }
}

ReadActivity

rawQuery() ๋Œ€์‹  query() ์‚ฌ์šฉํ•˜๊ธฐ

package com.tutorial.c60

import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class ReadActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_detail)

        val titleView = findViewById<TextView>(R.id.read_title)
        val contentView = findViewById<TextView>(R.id.read_content)

        val db = DBHelper(this).readableDatabase

        // ์ตœ์‹  ์ž…๋ ฅ ๋ฐ์ดํ„ฐ 1๊ฑด์„ ์–ป์–ด์„œ ํ…์ŠคํŠธ๋ทฐ์— ์ถœ๋ ฅํ•˜๊ธฐ
//        val cursor = db.rawQuery("select title, content from tb_memo " +
//                "order by _id desc limit 1", null)

        val cursor = db.query("tb_memo", arrayOf("title, content"),
            null, null, null, null,
            "_id desc limit 1")

        while(cursor.moveToNext()){
            titleView.text = cursor.getString(0)
            contentView.text = cursor.getString(1)
        }
        db.close()
    }
}
profile
์Šต๊ด€์ด ๋  ๋•Œ๊นŒ์ง€ ๐Ÿ“

0๊ฐœ์˜ ๋Œ“๊ธ€