Archives
Recent Posts
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Today
Total
관리 메뉴

안드로이드 개발자의 창고

[44일차 Android] SQLiteDatabase 본문

Computer/Android

[44일차 Android] SQLiteDatabase

Wise-99 2023. 7. 10. 19:17

 

 

 

출처 : 안드로이드 앱스쿨 2기 윤재성 강사님 수업 PPT

 

 

 

📖 SQLiteDatabase

  • 안드로이드에서 사용하는 내장 데이터 베이스로 표준 SQL문을 사용하는 관계형 데이터 베이스
  • MySQL과 유사한 문법을 사용하고 있으며 일반적인 관계형 데이터 베이스가 가지고 있는 기능을 가지고 있다.
  • 임베디드형 데이터베이스로써 데이터베이스를 사용하는 애플리케이션에 셋팅되는 데이터 베이스이다.
  • 안드로이드 OS에 내장되어 있으며 개발자가 만드는 애플리케이션은 안드로이드 OS에게 쿼리문을 전달하고 안드로이드 OS가 직접 데이터 베이스에 대한 처리를 하게 된다.
  • 안드로이드에서의 SQLite 사용은 쿼리문을 이용하는 방법제공되는 클래스를 사용하는 방법 두 가지가 있다.

 

SQLite OpenHelper

 

  • 안드로이드에서 SQLite 데이터 베이스를 사용하려면 SQLiteOpenHelper를 상속받은 클래스를 만들어야 한다.
  • 이 클래스는 사용할 데이터베이스의 이름을 설정하는 것 뿐만 아니라 다음 기능들을 제공하고 있다.
    • 지정된 데이터베이스 파일을 사용하려고 할 때 파일이 없으면 파일을 만들고 onCreate 메서드를 호출한다. onCreate 메서드에서는 테이블을 만드는 쿼리를 실행해주면 된다.
    • 애플리케이션을 서비스하다가 데이터 베이스 구조를 변경하려면 데이터베이스의 버전을 변경하면 된다. 버전을 변경하면 onUpgrade 메서드가 호출되고 여기에서 테이블을 새로운 구조로 변경해주는 작업을 해주면 된다.

 

ContentValue

  • 클래스를 이용하는 방법을 사용할 때 가장 중요한 클래스
  • ContentValue 클래스는 값을 저장할 때 이름을 부여하는 클래스로써 값을 저장할 때 사용하는 이름은 테이블의 컬럼 이름과 매칭된다.
  • ContentValue에 저장한 데이터는 테이블의 컬럼과 매칭되어 insert, update 등에 사용된다.

 

 

 

예제 코드

DBHelper.kt

// Test.db : 사용할 데이터 베이스 파일의 이름
// null : NullFactory, Null에 대한 처리를 어떻게 할 것인가에 대한 값
// 1 : 버전

class DBHelper(context: Context) : SQLiteOpenHelper(context, "Test.db", null, 1) {
    // 데이터베이스 파일이 없으면 만들고 이 메서드를 호출
    // 테이블을 생성 코드 작성
    override fun onCreate(db: SQLiteDatabase?) {
        // 테이블 구조 정의

        // create table 테이블이름
        // (컬럼이름 자료형 제약 조건...)
        
        // 자료형 : 정수 - Integer, 문자열 - text, 실수 - real, 날짜 - date
        // 제약조건 : 저장할 수 있는 값에 대한 조건
        // primary key : null이나 중복된 값을 허용X,각 행을 구분할 수 있는 값을 저장하기 위해 사용
        // autoincrement : 컬럼에 저장할 값을 지정하지 않으면 1부터 1씩 증가되는 값이 자동 저장
        // not null : null 값 허용X

        val sql = """create table TestTable
            (idx integer primary key autoincrement,
            textData text not null,
            intData integer not null,
            doubleData real not null,
            dateData date not null)
        """.trimIndent()

        // 쿼리문 수행
        db?.execSQL(sql)
    }

    // 데이터베이스 파일 버전이 변경되어 있을 떼 호출되는 메서드
    // 부모 생성자 마지막에 넣어준 버전 번호가 데이터 베이스 파일에 기록 버전보다 높을 때 호출
    // 과거에 만들어진 테이블의 구조가 될 수 있도록 테이블을 수정 작업 코드 작성
    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        TODO("Not yet implemented")
    }
}

 

 

 

MainActivity.kt

class MainActivity : AppCompatActivity() {

    lateinit var activityMainBinding : ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(activityMainBinding.root)

        activityMainBinding.run {
            // 데이터 저장
            button.setOnClickListener {
                // 현재 시간을 구해 년-월-일 양식의 문자열 생성
                val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
                val now = sdf.format(Date())

                // 저장할 정보를 가지고 있는 TestClass 객체 생성
                val obj1 = TestClass(0, "문자열1", 100, 11.11, now)
                DAO.insertData(this@MainActivity, obj1)

                val obj2 = TestClass(0, "문자열2", 200, 22.22, now)
                DAO.insertData(this@MainActivity, obj2)
            }
            
            // 특정 데이터 불러오기
            button2.setOnClickListener {

                val dataList = DAO.selectAllData(this@MainActivity)

                // 출력
                textView.text = ""

                for(obj in dataList){
                    textView.append("idx : ${obj.idx}\n")
                    textView.append("textData : ${obj.textData}\n")
                    textView.append("intData : ${obj.intData}\n")
                    textView.append("doubleData : ${obj.doubleData}\n")
                    textView.append("dateData : ${obj.dateData}\n\n")
                }
            }

            // 전체 데이터 불러오기
            button3.setOnClickListener {
                val obj = DAO.selectData(this@MainActivity,1)

                textView.text = "idx : ${obj.idx}\n"
                textView.append("textData : ${obj.textData}\n")
                textView.append("intData : ${obj.intData}\n")
                textView.append("doubleData : ${obj.doubleData}\n")
                textView.append("dateData : ${obj.dateData}\n")
            }

            // 데이터 수정
            button4.setOnClickListener {
                // 특정 데이터를 선택하여 TestClass 객체로 받는다.
                val obj = DAO.selectData(this@MainActivity, 1)

                // 객체의 데이터 수정
                obj.textData = "새로운 문자열"
                
                // 수정된 객체를 다시 저장하여 데이터 수정
                DAO.updateData(this@MainActivity, obj)
            }

            // 데이터 삭제
            button5.setOnClickListener {
                DAO.deleteData(this@MainActivity, 1)
            }
        }
    }
}

data class TestClass(var idx:Int,
                     var textData:String,
                     var intData:Int,
                     var doubleData:Double,
                     var dateData:String)

 

 

DAO.kt - 쿼리문 이용 방식

class DAO {
    companion object{
        // Insert : 저장
        fun insertData(context: Context, data:TestClass){
            // autoinctement가 있는 컬럼은 제외하고 나머지만 지정
            val sql = """insert into TestTable
                | (textData, intData, doubleData, dateData)
                | values (?, ?, ?, ?)
            """.trimMargin()

            // ?에 설정할 값을 배열에 담는다.
            val arg1 = arrayOf(
                data.textData, data.intData, data.doubleData, data.dateData
            )

            // 데이터베이스 오픈
            val sqliteDatabase = DBHelper(context)
            // 쿼리 실행(쿼리문 ?에 셋팅할 값 배열)
            sqliteDatabase.writableDatabase.execSQL(sql, arg1)
            // 데이터 베이스를 닫아준다.
            sqliteDatabase.close()
        }

        // Select : 조건에 맞는 행 가져오기
        fun selectData(context: Context, idx:Int):TestClass{
            // 쿼리문
            val sql = "select * from TestTable where idx=?"
            // ?에 들어갈 값(문자열 배열)
            val arg1 = arrayOf("$idx")

            val dbHelper = DBHelper(context)
            // 쿼리 실행
            val cursor = dbHelper.writableDatabase.rawQuery(sql, arg1)
            cursor.moveToNext()

            // 컬럼 이름을 지정하여 컬럼의 순서 값을 가져오기
            val idx1 = cursor.getColumnIndex("idx")
            val idx2 = cursor.getColumnIndex("textData")
            val idx3 = cursor.getColumnIndex("intData")
            val idx4 = cursor.getColumnIndex("doubleData")
            val idx5 = cursor.getColumnIndex("dateData")

            // 데이터 가져오기
            val idx = cursor.getInt(idx1)
            val textData = cursor.getString(idx2)
            val intData = cursor.getInt(idx3)
            val doubleData = cursor.getDouble(idx4)
            val dateData = cursor.getString(idx5)

            // 불러온 데이터로 객체 생성
            val testClass = TestClass(idx, textData, intData, doubleData, dateData)

            dbHelper.close()
            
            // 데이터로 생성한 객체 반환
            return testClass
        }

        // Select All : 모든 행 가져오기
        fun selectAllData(context: Context) : MutableList<TestClass>{

            val sql = "select * from TestTable"

            // 데이터베이스 오픈
            val dbHelper = DBHelper(context)
            // 쿼리 실행
            val cursor = dbHelper.writableDatabase.rawQuery(sql, null)
            
            val dataList = mutableListOf<TestClass>()
            
            // cursor 객체는 쿼리문에 맞는 행에 접근할 수 있는 객체
            // 처음에는 아무 행도 가리키고 있지 않음
            // moveToNext 메서드 호출 시 다음 행에 접근 가능
            // 이 때 접근할 행이 있으면 true, 없으면 false를 반환
            while (cursor.moveToNext()){
            
                // 컬럼 이름을 지정하여 컬럼의 순서 값을 가져오기
                val idx1 = cursor.getColumnIndex("idx")
                val idx2 = cursor.getColumnIndex("textData")
                val idx3 = cursor.getColumnIndex("intData")
                val idx4 = cursor.getColumnIndex("doubleData")
                val idx5 = cursor.getColumnIndex("dateData")

                // 데이터 가져오기
                val idx = cursor.getInt(idx1)
                val textData = cursor.getString(idx2)
                val intData = cursor.getInt(idx3)
                val doubleData = cursor.getDouble(idx4)
                val dateData = cursor.getString(idx5)

                val testClass = TestClass(idx, textData, intData, doubleData, dateData)
                dataList.add(testClass)
            }

            dbHelper.close()
            
            // 데이터로 생성한 객체를 저장한 리스트 반환
            return  dataList
        }

        // Update : 조건에 맞는 행의 컬럼 값 수정
        fun updateData(context: Context, obj:TestClass){
            // 쿼리문
            // idx가 ?인 행의 textData, intData, doubleData, dateData 칼럼의 값을 변경한다.
            val sql = """update TestTable
                | set textData = ?, intData=?, doubleData = ?, dateData = ?
                | where idx = ?
            """.trimMargin()

            // ?에 들어갈 값
            val args = arrayOf(obj.textData, obj.intData, obj.doubleData, obj.dateData, obj.idx)
            // 쿼리 실행
            val dbHelper = DBHelper(context)
            dbHelper.writableDatabase.execSQL(sql, args)
            dbHelper.close()
        }

        // Delete : 조건에 맞는 행을 삭제한다.
        fun deleteData(context: Context, idx: Int){
            // 쿼리문
            val sql = "delete from TestTable where idx = ?"
            // ?에 들어갈 값
            val args = arrayOf(idx)
            // 쿼리 실행
            val dbHelper = DBHelper(context)
            dbHelper.writableDatabase.execSQL(sql, args)
            dbHelper.close()
        }
    }
}

 

 

 

 

DAO.kt - 제공되는 클래스(ContentValue) 이용 방식

class DAO {
    companion object{
        // Insert : 저장
        fun insertData(context: Context, data:TestClass){
            // 컬럼 이름과 데이터를 설정하는 객체
            val contentValues = ContentValues()
            
            // 컬럼 이름, 값 지정
            contentValues.put("textData", data.textData)
            contentValues.put("intData", data.intData)
            contentValues.put("doubleData", data.doubleData)
            contentValues.put("dateData", data.dateData)

            val dbHelper = DBHelper(context)
            
            // 데이터를 저장할 테이블의 이름,
            // null값을 어떻게 처리할 것인가,
            // 저장할 데이터를 가지고 있는 객체
            dbHelper.writableDatabase.insert("TestTable", null, contentValues)
            
            dbHelper.close()
        }

        // Select : 조건에 맞는 행 하나 가져오기
        fun selectData(context: Context, idx:Int):TestClass{
            val dbHelper = DBHelper(context)
            
            // 첫 번째 : 테이블명
            // 두 번째 : 가져오고자 하는 컬럼의 이름 목록, null을 넣어주면 모두 가져온다.
            // 세 번째 : 특정 행을 선택하기 위한 조건절
            // 네 번째 : 세 번째에 들어가는 조건절의 ? 에 셋팅될 값 배열
            // 다섯 번째 : Group by의 기준 컬럼
            // 여섯 번째 : Having절에 들어갈 조건절
            // 일곱 번째 : Having절의 ?에 셋팅될 값 배열
            val selection = "idx = ?"
            val args = arrayOf("$idx")
            val cursor = dbHelper.writableDatabase.query("TestTable", null, selection, args, null, null, null)

            cursor.moveToNext()

            // 컬럼의 이름을 지정하여 컬럼의 순서 값을 가져온다.
            val idx1 = cursor.getColumnIndex("idx")
            val idx2 = cursor.getColumnIndex("textData")
            val idx3 = cursor.getColumnIndex("intData")
            val idx4 = cursor.getColumnIndex("doubleData")
            val idx5 = cursor.getColumnIndex("dateData")

            // 데이터를 가져온다.
            val idx = cursor.getInt(idx1)
            val textData = cursor.getString(idx2)
            val intData = cursor.getInt(idx3)
            val doubleData = cursor.getDouble(idx4)
            val dateData = cursor.getString(idx5)

            val testClass = TestClass(idx, textData, intData, doubleData, dateData)

            dbHelper.close()
            return testClass
        }

        // Select All : 모든 행을 가져오기
        fun selectAllData(context: Context) : MutableList<TestClass>{
            var dbHelper = DBHelper(context)

            val cursor = dbHelper.writableDatabase.query("TestTable", null, null, null ,null, null, null)

            val dataList = mutableListOf<TestClass>()
            
            // cursor 객체에는 쿼리문에 맞는 행에 접근할 수 있는 객체
            // 처음에는 아무 행도 가리키고 있지 않는다.
            // moveToNext 메서드를 호출하면 다음 행에 접근 가능
            // 이 때 접근할 행이 있으면 true, 없으면 false를 반환
            while (cursor.moveToNext()){
                // 컬럼 이름을 지정하여 컬럼의 순서 값을 가져오기
                val idx1 = cursor.getColumnIndex("idx")
                val idx2 = cursor.getColumnIndex("textData")
                val idx3 = cursor.getColumnIndex("intData")
                val idx4 = cursor.getColumnIndex("doubleData")
                val idx5 = cursor.getColumnIndex("dateData")

                // 데이터 가져오기
                val idx = cursor.getInt(idx1)
                val textData = cursor.getString(idx2)
                val intData = cursor.getInt(idx3)
                val doubleData = cursor.getDouble(idx4)
                val dateData = cursor.getString(idx5)

                val testClass = TestClass(idx, textData, intData, doubleData, dateData)
                dataList.add(testClass)
            }

            dbHelper.close()
            return  dataList
        }

        // Update : 조건에 맞는 행의 컬럼 값을 수정
        fun updateData(context: Context, obj:TestClass){
            // 컬럼과 값을 지정하는 ContentValues를 생성한다.
            val cv = ContentValues()
            cv.put("textData", obj.textData)
            cv.put("intData", obj.intData)
            cv.put("doubleData", obj.doubleData)
            cv.put("dateData", obj.dateData)
            
            // 조건절
            val condition = "idx = ?"
            
            // ?에 들어갈 값
            val args = arrayOf("${obj.idx}")
            
            // 수정
            val dbHelper = DBHelper(context)
            // 테이블 명, content values, 조건절, ?에 들어갈 값
            dbHelper.writableDatabase.update("TestTable", cv, condition, args)
            dbHelper.close()
        }

        // Delete : 조건에 맞는 행 삭제
        fun deleteData(context: Context, idx: Int){
            // 조건절
            val condition = "idx = ?"
            // ?에 들어갈 값
            val args = arrayOf("$idx")

            val dbHelper = DBHelper(context)
            dbHelper.writableDatabase.delete("TestTable", condition, args)
            dbHelper.close()
        }
    }
}

'Computer > Android' 카테고리의 다른 글

[50일차 Android] Preferences  (0) 2023.07.17
[50일차 Android] Content Provider  (0) 2023.07.14
[44일차 Android] assets  (0) 2023.07.10
[44일차 Android] Raw  (0) 2023.07.10
[43일차 Android] 파일 입출력  (0) 2023.07.10