본문 바로가기
안드로이드

[안드로이드] 저장소에 데이터 보관하기(1) - 데이터베이스에 보관하기

by Bakhwee_Bug 2022. 9. 26.

데이터베이스 프로그래밍이란 데이터베이스에 테이블을 만들고

SQL을 이용해 데이터를 삽입, 조회, 갱신, 삭제하는 방법이다

 

안드로이드폰에서 이용하는 데이터 베이스 관리 시스템

오픈소스로 만들어진 SQLite이다.

 

 <SQLite>

  • 테이블의 데이터를 앱의 저장소에 파일로 저장한다
  • 외부 앱에서는 접근할 수 없다
  • 코드에서는 SQL 질의문만 작성하면 된다
  • 실제 데이터는 SQLite가 관리해준다

<질의문 작성하기>

  • SQLite를 작성하려면 SQLiteDatabase라는 API를 이용해야 한다.
  • SQLiteDatabase 객체는 openCreateDatabase() 함수를 호출해서 얻는다.
val db = openCreateDatabase("testdb", Context.MODE_PRIVATE, null)
  •  openCreateDatabase() 함수
    • 첫 번째 매개변수로 전달한 DB 파일을 연다
    • SQLiteDatabase 객체를 돌려준다
    • 만약 파일이 없으면 새로 만든다
      • SQLiteDatabase 객체에 정의된 다음 함수를 이용하면 질의문을 실행할 수 있다.
public void execSQL(String sql, Object[] bingArgs)
public Cursor rawQuery(String sql, String[] selectionArgs)
  • execSQL(), rawQuery() 함수
    • 첫 번째 매개변수에 질의문을 전달한다
    • 두 번째 매개변수에 질의문에서 ?문자에 대응하는 값을 배열로 전달한다.
      • 예를 들어 질의문에 물음표를 3개 작성했다면 크기가 3인 배열을 전달해 순서대로 물음표로 표시한 곳에 대입한다.
  • execSQL() 함수
    • 질의문 중에서 create, alter, drop, insert, update, delete 문을 실행하는 함수
db.execSQL("create table USER_TB (" + "_id integer primary key autoincrement," + "name not null, " + "phone)")
  • 위의 코드는 db 객체가 가리키는 DB파일에 execSQL() 함수로 create 문을 실행해 테이블을 만드는 예이다.

 

  • 이렇게 만든 테이블에 데이터를 넣으려면 다음처럼 execSQL() 함수로 insert문을 실행하면 된다.
db.execSQL("insert into USER_TB (name, phone) values (?,?)",
	arrayOf<String>("kkang","0101111"))
  • 테이블에 저장된 데이터를 조회할 때는 rawQuery() 함수로 select 문을 실행한다.

 

  • rawQuery() 함수의 반환값은 Cursor 객체이다.
    • Cursor 객체는 테이블에서 조회한 행의 집합 정도로 생각하면 된다.
val cursor = db.rawQuery("select * from USER_TB", null)
  • 조회한 행의 열 데이터를 가져오려면
    1. 먼저 Cursor 객체로 행을 선택하고
    2. 그 행의 열 데이터를 가져온다

 

  • Cursor 객체로 행을 선택할 때는 moveTo~로 시작하는 다음 함수를 이용한다
    • 이 함수들은 선택한 행이 있으면 true를 반환하고 없으면 false를 반환한다
      • public abstract boolean moveToFirst() : 첫번째 행을 선택한다.
      • public abstract boolean moveToLast() : 마지막 행을 선택한다.
      • public abstract boolean moveToNext() : 다음 행을 선택한다.
      • public abstract boolean moveToPosition(int position) : 매개변수로 지정한 위치의 행을 선택한다.
      • public abstract boolean moveToPrevious() : 이전 행을 선택한다.

 

  • Cursor 객체로 선택한 행의 열 데이터를 가져오려면 타입에 따라 getString(), getInt() 등의 함수를 이용한다.
    • 이 함수의 매개변수에는 가져올 데이터가 저장된 열의 인덱스를 전달한다.
      • public abstract String getString(int columnIndex) 
      • public abstract int getInt(int columnIndex) 
      • public abstract double getDouble(int columnIndex) 
while(cursor.moveToNext()){
	val name = cursor.getString(0)
  	val phone = cursor.getString(1)
}

 

지금까지 질의문을 실행하는 SQLiteDatabase 클래스의 rawQuery(), execSQL() 함수를 살펴보았다.

 

이 함수를 이용하지 않고 insert(), update(), delete(), query() 함수를 이용해도 된다.

  • 이 함수는 질의문의 각 항목을 매개변수로 대입하면 질의문으로 만들어 실행해준다.
  • 즉, 질의문을 코드에서 직접 작성하지 않고 항목별 정보만 매개변수로 대입해 주면 된다.
    • public long insert(String table, String nullColumnHack, ContentValues values)
    • public int update(String table, ContentValues values, String whereClause, String[] whereArgs)
    • public int delete(String table, String whereClause, String[] whereArgs)
    • public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)

 

  • insert(), update() 함수의 매개변수에서 ContentValues 객체는 열 데이터의 집합이다.
    • Map 객체처럼 키-값 형태로 데이터 집합을 저장하는데 이때 키에는 테이블의 열 이름을 지정한다

 

  • insert() 함수 예시
val values = ContentValues()
values.put("name", "bak-hwee")
values.put("phone", "0101234")
db.insert("USER_TB", null, values)

 

  • query() 함수 예시
val cursor = db.query("USER_TB", arrayOf<String>("name","phone"), "phone=?", arrayOf<String>("0101234"), null, null, null)
  • query() 함수의 각 매개변수는 다음과 같다
    • table: 조회할 테이블 명
    • columns: 가져올 값이 담긴 열 이름을 배열로 지정
    • selection: select 문의 where 절 뒤에 들어갈 문자열
    • selectionArgs: 질의문에서 ?에 들어갈 데이터 배열
    • groupBy: select 문의 group by 조건
    • having: select 문의 having 조건
    • orderBy: select 문의 order by 조건
  • 위의 예시에서는 
    • table은 USER_TB
    • columns는 arrayOf<String>("name","phone")
    • selection은 "phone=?"
    • selectionArgs는 arrayOf<String>("0101234")
    • 나머지는 null

 

 

<데이터베이스 관리하기>

  • SQLite 데이터베이스를 이용할 때는 질의문을 실행해야 하므로 반드시 SQLiteDatabase 객체를 이용해야 한다.
  • 추가로 SQLiteOpenHelper 클래스를 이용하면 데이터베이스 프로그램을 좀 더 구조적으로 작성할 수 있다.

 

 

[Kotlin] 클래스 6—인터페이스(interface), 추상 클래스(abstract class)

Kotlin에서 interface와 abstract class를 정의하고 사용하는 방법과 이들의 특징에 대하여 다룹니다.

medium.com

 

 

class DBHelper(context: Context) : SQLiteOpenHelper(context, "testdb", null, 1){
    override fun onCreate(db: SQLiteDatabase?){
    }
    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int){
        
    }
}
  • SQLiteOpenHelper 클래스를 상속 받을 때 상위 클래스의 생성자를 호출하면서 적절한 정보를 남겨줘야 한다
    • 위 코드에서 "testDB"는 DB 파일명
    • 1은 개발자가 숫자로 지정하는 DB 버전 정보
  • onCreate(), onUpgrade() 함수는 SQLiteOpenHelper의 추상 함수이므로 하위 클래스에서 반드시 재정의 해야한다.
    • onCreate(): 앱이 설치된 후 SQLiteOpenHelper클래스가 이용되는 순간 한 번 호출한다
      • 이 함수에는 데이터베이스의 테이블을 생성하는 코드를 주로 작성한다.
    • onUpgrade(): 생성자에 지정한 DB 버전 정보가 변경될 때마다 호출한다.
      • 이 함수에는 테이블의 스키마를 변경하는 코드를 주로 작성한다.
        • 스키마: 데이터의 구조나 표현 방법, 관계 등을 나타낸다.
  • 이처럼 테이블을 생성하거나 스키마를 변경하는 코드는 SQLiteOpenHelper에 작성하고
  • 데이터를 조작하는 질의문은 다른 곳에서 작성하는 구조로 만든다.
  • SQLiteOpenHelper클래스를 이용한다면 질의문을 실행하는 SQLiteDatebase 객체도 SQLiteOpenHelper 클래스를 이용해 생성한다.
val db: SQLiteDatabase = DBHelper(this).writableDatabase

SQLiteOpenHelper클래스의 readableDatabase나 writableDatabase 속성으로 데이터베이스 객체를 생성한다.

 

 

댓글