학교 모바일 응용 수업 복습
SQLite
클라이언트 어플리케이션에 주로 사용하는 경량 내장형 DBMS
- 관계형 데이터베이스
- http:///www.sqlite.org
- 안드로이드, iOS, 그리고 웹 브라우저 등에서 사용
→ 안드로이드 경우 프레임워크에 기본 내장
기기에 자료를 영구적으로 저장해야할 경우 적용
- 휴대폰 내부에 파일로 DB가 만들어짐
- 라이브러리 형태로 호출하여 사용 (클래스 import)
DB 사용 절차
SQLiteOpenHelper 상속 클래스 작성 → helper 객체 생성 → helper를 사용하여 SQLiteDatabase 객체 획득 → SQLiteDatabase 객체를 사용하여 Query 수행 → helper 객체 (및 관련 객체) Close 수행
1. SQLiteOpenHelper 상속 클래스 작성
class MyDBHelper: SQLiteOpenHelper ( ... ) {
MyDBHelper() // 생성자
onCreate() // 테이블 생성
onUpgrade() // DB 수정이 필요한 경우
}
- DB를 관리하는 클래스
- :SQLiteOpenHelper 안받아도 되지만 도움받으면 편함
2. helper 객체 생성
val helper = MyDMHelper ( ... )
3. helper를 사용하여 SQLiteDatabase 객체 획득
val writableDB = helper.writableDatabase // 쓰기 전용
// insert, update, delete
val readableDB = helper.readableDatabase // 읽기 전용
// select
- SQLiteDabase는 실제 DB를 의미
4. SQLiteDabase 객체를 사용하여 Query 수행
- 메소드 사용 방식
writableDB.insert() // 자료 저장 시
writableDB.update() // 자료 수정 시
writableDB.delete() // 자료 삭제 시
writableDB.query() // 자료 검색 시
- SQL 문 직접 작성 방식
writableDB.execSQL() // insert, update, delete 사용 시
writableDB.rawQuery() // select 사용 시
* 필요에 따라 선택
5. helper 객체 (및 관련 객체) Close 수행
helper.close()
// Cursor 를 사용하였을 경우 Cursor.close() <=- select 사용 시
SQLiteOpenHelper
데이터베이스를 편리하게 사용할 수 있도록 도와주는 클래스 → 상속하여 사용
- 데이터베이스 저장 파일 생성. DB 없으면 알아서 만들어줌
- 테이블 생성
- 테이블 업그레이드, 기본 샘플 데이터 추가 등
- SQLiteDatabase 객체 제공
필수 재정의 메소드
- 생성자 : 사용할 DB 파일 명 및 DB 버전을 지정
- onCreate()
- 사용할 테이블을 SQL을 사용하여 생성
- 샘플이 필요할 경우 테이블 생성 후 샘플 추가 문장 작성
- onUpgrade()
- 데이블 구조를 변경해야 할 필요가 있을 때 사용
- 특별히 재정의하지 않아도 무방
SQLiteOpenHelper 상속 클래스 작성
FoodDBHelper 전체 코드
class FoodDBHelper (context: Context?) : SQLiteOpenHelper(context, DB_NAME, null, 1) {
val TAG = "FoodDBHelper"
companion object {
const val DB_NAME = "food_db"
const val TABLE_NAME = "food_table"
const val COL_FOOD = "food"
const val COL_COUNTRY = "country"
}
override fun onCreate(db: SQLiteDabase?) {
val CREATE_TABLE =
"CREATE TABLE ${TABLE_NAME} (${BaseColumns._ID} INTEGER PRIMARY KEY AUTOINREMENT, " +
"${COL_FOOD} TEXT, ${COL_COUNTRY} TEXT }"
Log.d(TAG, CREATE_TABLE)
db?.execsQL(CREATE_TABLE)
}
override fun onUpgrade(db: SQLiteDatabase?, oldVer: Int, newVer: Int) {
val DROP_TABLE = "DROP TABLE IF EXISTS ${TABLE_NAME}"
db?.execSQL(DROP_TABLE)
onCreate(db)
}
}
1. SQLiteOpenHelper 상속
- 매개 변수 : context, DB 명, cursorFactory, DB ver.
class FoodDBHelper (context: Context?) : SQLiteOpenHelper(context, DB_NAME, null, 1//← 얘 바꾸면 onUpgrade()) {
2. DB 및 테이블, 테이블 컬럼명 등을 companion object로 생성하여 보관
→ 해당 항목명의 사용 일관성을 위해
- ex ) FoodDBHelper.TABLE_NAME
// companion은 static을 대체
companion object {
const val DB_NAME = "food_db"
const val TABLE_NAME = "food_table"
const val COL_FOOD = "food"
const val COL_COUNTRY = "country"
}
3. 최초로 readableDatabase 또는 writableDatabase 사용시 호출
- DB의 테이블 생성 및 필요시 샘플 데이터 추가
// db: SQLiteDabase? -> null일 수도 있는 객체임
override fun onCreate(db: SQLiteDabase?) {
4. BaseColumns 인터페이스의 _ID 속성(i_d) 지정
→ 다른 안드로이드 요소에서 필요한 경우가 있음
val CREATE_TABLE = // 테이블 새로 만듦
// _ID == '_id'
// 안드로이드 항상 primary key는 _ID로 하자(약속) -> 외부에서 쉽게 파악. 필수x 권장o
"CREATE TABLE ${TABLE_NAME} (${BaseColumns._ID} INTEGER PRIMARY KEY AUTOINREMENT, " +
"${COL_FOOD} TEXT, ${COL_COUNTRY} TEXT }"
Log.d(TAG, CREATE_TABLE)
db?.execsQL(CREATE_TABLE)
5. 새로운 버전의 DB를 사용할 필요가 있을 때 사용
- 버전 같음 → 실행x
- 버전 다름 → 실행o
// oldVer이 1임
override fun onUpgrade(db: SQLiteDatabase?, oldVer: Int, newVer: Int) {
val DROP_TABLE = "DROP TABLE IF EXISTS ${TABLE_NAME}"
db?.execSQL(DROP_TABLE)
onCreate(db)
}
Helper 객체 생성
DB 사용 부분에서 객체 생성
Helper 객체 생성 시의 동작
- 생성자에 의해 DB파일이 안드로이드 내부저장소에 생성
- 실기기는 보안 문제로 폴더 외부 접근이 안되므로 에뮬레이터 상에서만 확인 가능
- [Device File Explorer] 사용
- 에뮬레이터 선택 후 [File Explorer] 선택
SQLiteDabase
Helper 클래스에 의해 관리되는 데이터베이스 클래스
- DB 작업 Query를 수행
Helper 클래스를 사용하여 획득
- 읽기 전용 (select)
val myDB : SQLiteDatabase = myDBHelper.readableDatabase
- 읽기/쓰기 겸용 (select/update/delete)
val myDB : SQLiteDatabse = myDBHelper.writableDatabase
SQL을 직접 사용하거나 관련 메소드를 사용하여 Query 수행
모든 작업 수행 후 helper 객체를 통해 반드시 close()하여 종료
SQLiteDatabase Query
데이터 삽입
Query 전용 함수 사용 or SQL 사용
- 전용 함수 사용은 Content Provider 사용과 동일
데이터 삽입 - insert() or execSQL()
- ContentValues 객체 생성 후 입력할 데이터 값 설정 후 insert() 사용
→ 반환값이 있으므로 삽입 결과 확인 가능 - execSQL()를 사용하여 SQL 직접 작성 후 수행
- 수행 완료 후 helper.close() 호출
- 전용함수 사용 방식
// helper는 FoodDBHelper 객체
val db = helper.writableDatabase
val newRow = ContentValues() // insert할 내용물 저장
newRow.put("food", "된장찌개") // id는 autoinrement니까 빼고 함
newRow.put("country", "한국")
db.insert("food_table", null, newRow)
helper.close()
- SQL 직접 사용방식
// 방법 1 - 문자열 표시 시 '' 사용 주의
db.execSQL("INSERT INTO food_table " +
"VALUES (NULL, '된장찌개', '한국')")
// 방법 2 - 매개변수 결합 방식, execSQL(sql, 매개변수 배열)
db.execSQL("insert into ${FoodDBHelper.TABLE_NAME} " +
"value (null, ?, ?)", arrayOf("된장찌개", "한국"))
데이터 수정
데이터 수정 - update() or execSQL()
- ContentValues 객체에 변경할 값 및 조건 설정 후 update() 사용
- execSQL() 메소드를 사용하여 SQL 직접 작성 후 수행
- 전용함수 사용방식
val db = helper.writableDatabase
val newRow = ContentValues()
newRow.put("country", "한국")
val whereClause = "food_?" // 수정할 row 검색 조건 - 여러 개일 경우 A=? and B=?
val whereArgs = arrayOf("된장찌개")
db.update("food_table", updateRow, whereClause, whereArgs)
helper.close()
- SQL 직접 사용 방식
db.execSQL("UPDATE food_table " +
" SET country='한국' WHERE food='된장찌개'")
데이터 삭제
데이터 삭제 - delete() or execSQL()
- 삭제대상 검색 조건 지정 후 delete() 수행
- execSQL 메소드를 사용하여 SQL 직접 작성 후 수행
- 전용함수 사용방식
val db = helper.writableDatabase
val whereClause = "food_?"
val whereArgs = arrayOf("된장찌개")
db.delete("food_table", whereClause, whereArgs)
helper.close()
- SQL 직접 사용방식
db.execSQL("DELETE FROM food_table WHERE food='된장찌개'")
데이터 검색
데이터 검색 - query() or rawQuery()
- 조건문 지정 후 query() 수행
- rawQuery 메소드를 사용하여 SQL 직접 수행
- Cursor(데이터 반환 집합에 대한 레퍼런스) 값을 반환
- 사용 후 Helper 및 Cursor는 반드시 close() 적용
- 전용함수 사용방식
val db = helper.readableDatabase // 읽기 전용 사용 가능
val columns = arrayOf("_id", "food", "country") // 검색할 컬럼명, null 일 경우 모든 컬럼
val selection = "food=?" // 검색 조건
val selectionArgs = arrayOf("된장찌개")
val cursor = db.query(
"food_table", columns, selection, selectionargs,
null, null, null, null
)
- SQL 직접 사용 방식
val cursor = db.rawQuery("SELECT _id, food, country FROM" +
" food_table WHERE food='된장찌개'", null)
Cursor
Corsor
- select 문에 의해 반환한 레코드의 집합을 가리킴
- Cursor.moveToNext() : 다음 레코드가 있으면 true, 없으면 false
- Cursor.getTYPE(column_index)를 사용하여 값을 읽어옴
// DB 겁색 결과를 DTO에 저장하여 List에 보관하고자 할 경우
// val foodList = arrayListOf<FoodDTO>()
with(cursor) {
while (moveToNext()){
val id = getInt( getColumnIndex("_id"))
val food = getString(getColumnIndex("food"))
val country = getString(getColumnIndex("country"))
Log.d(TAG, "$id - $food ($country)")
// 결과를 DTO 객체에 저장후 List에 보관
// val dto = FoodDTO(id, food, country)
// foodList.add(dto)
}
}
cursor.close()
helper.close()
'공부 > 안드로이드' 카테고리의 다른 글
[Android/Kotlin] 주간 달력 만들기 (0) | 2024.02.21 |
---|---|
[Android/Kotlin] fragment에서 fragment로 이동 (0) | 2024.02.21 |
[Android/Kotlin] 안드로이드 spinner(스피너) 배경색 적용 (0) | 2024.02.21 |
[Android/Kotlin] 안드로이드 스튜디오 알림 안뜸 해결 (0) | 2023.11.05 |
[Android/Kotlin] 뷰바인딩 (0) | 2023.09.27 |