[Android] 모바일 데이터베이스(Database)와 테이블(Table) 생성
모든 내용은 Do it! 안드로이드 앱 프로그래밍을 바탕으로 정리한 것입니다.
모바일 데이터베이스
많은 양의 데이터를 체계적으로 관리하기 위해서 사용
(↔ SharedPreferences는 데이터를 간단하게 저장할 때!)
표준 SQL 문으로 데이터를 조회하는 관계형 DB를 단말에서 사용할 수 있다면 적은 양의 데이터라도 접근이 가능하므로 더 효율적!
SQLite
안드로이드는 임베디드 데이터베이스(Embedded Database)로 개발된 경량급 관계형 데이터 베이스 SQLite를 가짐
- 파일로 만들어진 하위 수준의 구조를 가지면서 DB의 기능까지 그대로 사용할 수 있도록 만든 것
- 저장될 때는 파일로 저장되므로 DB의 복사, 이동, 삭제가 매우 쉬움
- 데이터 조회 속도가 빠름
- 표준 SQL을 지원함
- 기존의 웹이나 PC에서 사용하던 업무용 앱의 데이터 관리 기능을 그대로 사용할 수 있음
- 원격 DB를 접근하는 SQL문을 로컬에서 똑같이 사용할 수 있음
∴ 앱의 개발 생산성↑, 향후 기능 변경에도 간단한 SQL 수정만으로 데이터 처리 방식을 바꿀 수 있음
데이터베이스와 테이블 생성
데이터베이스 ⊃ 테이블
데이터베이스는 여러 개의 테이블을 담는 그릇 → 우선 그릇을 만들거나 만들어진 그릇을 열고 닫을 수 있어야 함
public abstract SQLiteDatabase openOrCreateDatabase (String name, int mode, SQLiteDatabase.CursorFactory factory)
public abstract boolean deleteDatabase (String name)
public vodi execSQL (String sql) throws SQLException
- openOrCreateDatabase() 메서드 : 데이터베이스를 만들거나 여는 메서드
- 첫번째 파라미터 (String name) : 데이터베이스 이름 / 데이터베이스 파일명
- 두번째 파라미터 (int mode) : 사용모드 - MODE_PRIVATE 상수
- 세번째 파라미터 (factory) : 널(Null)이 아닌 객체를 지정할 경우, 쿼리의 결과 값으로 반환되는 데이터를 참조하는 커서를 만들어낼 수 있는 객체 전달
- 반환되는 SQLiteDatabase 객체는 name 변수로 지정한 DB에 접근할 수 있는 메서드를 정의하고 있으므로, 해당 메서드로 DB를 열거나 만든 후에는 SQLiteDatabase 객체를 참조해야 함
...
private void createDatabase(String name) {
printText("createDatabase 호출");
database = openOrCreateDatabase(name, MODE_PRIVATE, null);
printText(name + " 데이터베이스 생성");
}
...
- deleteDatabase() 메서드 : 데이터베이스를 삭제하는 메서드
- execSQL() 메서드 : 데이터베이스를 만들고 난 다음 SQL문을 실행할 때 사용하는 메서드
- SQLiteDatabase 객체에서 가장 중요한 메서드 중 하나
- 해당 메서드를 이용하여 테이블을 만들고, 레코드 추가와 같은 표준 SQL을 사용하는 여러 데이터 처리가 가능함
...
database.execSQL("create table if not exists " + name + "("
+ "_id integer PRIMARY KEY autoincrement,"
+ " name text, "
+ " age integer, "
+ " mobile text);");
...
database.execSQL("insert into " + tableName
+ "(name, age, mobile)"
+ " values "
+ "('June', 20, '010-1234-1234' )");
헬퍼(Helper) 클래스
데이터베이스를 만드는 것 외에도 테이블의 정의가 바뀌어서 스키마(Schema)를 업그레이드할 필요가 있을 때 사용하는 클래스
스키마(Schema)
- 데이터베이스의 구조와 제약조건에 관해 전반적인 명세를 기술한 것
- 속성(Attribute), 개체(Entity), 관계(Relation), 제약 조건들을 기술함
- 테이블의 구조는 필요에 따라 바뀔 수 있음
- ⚠ 테이블 안에 사용자가 저장한 데이터가 있는 경우, 그 데이터가 삭제되거나 수정되어야 할 수 있음
- 스키마를 수정할 때는 테이블이 이미 사용되고 있는 상태인지 구별한 뒤에 처리해야 함
헬퍼 클래스를 사용하기 위해서는 SQLiteOpenHelper 클래스를 사용해야 함
SQLiteOpenHelper 클래스 - 데이터베이스를 만들거나 열기 위해 필요한 작업들을 도와주는 역할
public SQLiteOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
- 첫번째 파라미터 (Context context) : 액티비티 안에서 만들 경우 this로 지정할 수 있음
- 두번째 파라미터 (String name) : 데이터 베이스의 이름
- 세번째 파라미터 (factory) : 데이터 조회 시 반환하는 커서를 만들어 낼 CursorFactory 객체
- 네번째 파라미터 (int version) : 데이터베이스 업그레이드를 위해 사용하며 기존에 생성되어 있는 데이터베이스 버전 정보와 다르게 지정하여 데이터베이스의 스키마나 데이터를 바꿀 수 있음
SQLiteOpenHelper 객체는 데이터베이스를 만들거나 열기 위해 필요한 작업을 도와주는 역할을 하지만,
해당 객체를 만든다고 해서 데이터베이스 파일이 바로 만들어지는 것은 아님!
파일 생성을 위해서는 getReabableDatabase() 또는 getWritableDatabase() 메서드를 호출해야 함
→ 이 클래스의 장점은 데이터베이스가 만들어지거나 업그레이드할 때 콜백 메서드가 호출됨
→ 데이터베이스 생성, 업그레이드 등 여러 가지 상태에 따라 콜백 메서드를 다시 정의하면 각각의 상태에 맞게 처리할 수 있음
public abstract void onCreate (SQLiteDatabase db)
public abstract void onOpen (SQLiteDatabase db)
public abstract void onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion)
DB 생성
DatabaseHelper.java
public class DatabaseHelper extends SQLiteOpenHelper {
public static String NAME = "employee.db";
public static int VERSION = 1;
public DatabaseHelper(@Nullable Context context) {
super(context, NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
// 데이터베이스 생성
Log.d("DatabaseHelper", "onCreate 호출");
String sql = "create table if not exists emp(" +
" _id integer PRIMARY KEY autoincrement," +
" name text," +
" age integer," +
" mobile text);";
sqLiteDatabase.execSQL(sql);
}
@Override
public void onOpen(SQLiteDatabase db) {
// 데이터베이스 열 때 호출
super.onOpen(db);
Log.d("DatabaseHelper", "onOpen 호출");
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int old, int recent) {
// 데이터베이스 업그레이드
Log.d("DatabaseHelper", "onUpgrade 호출 : " + old + " -> " + recent);
if (recent > 1) {
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS emp");
}
}
}
MainActivity.java
private void createDatabase(String name) {
printText("createDatabase 호출");
helper = new DatabaseHelper(this);
database = helper.getWritableDatabase(); // 파일 생성
printText(name + " 데이터베이스 생성");
}
데이터 조회
데이터베이스를 열고 조회하는 방법에 대해 알아보기
- rawQuery()
- 데이터 조회를 위해 표준 SQL은 "SELECT ... "를 사용하는데, 이 구문을 통해 반환되는 Cursor 객체를 받기 위한 메소드
- Cursor 객체는 테이블에 들어있는 각각의 레코드를 순서대로 접근할 수 있게 함
- 이 객체는 처음에 아무런 레코드를 가리키지 않음
- while 구문을 이용할 시, moveToNext() 메소드가 false 값을 반환할 때까지 레코드를 가져옴
- for 구문을 이용할 시, getCount() 메소드를 이용해 전체 레코드 개수를 알아내어 moveToNext() 메소드 사용
- Cursor는 사용한 후에 close() 메서드를 이용하여 닫아야 함
public void executeQuery() {
printText("executeQuery 호출");
Cursor cursor = database.rawQuery("select _id, name, age, mobile from emp", null);
int recordCount = cursor.getCount();
printText("레코드 개수 : "+recordCount);
for (int i = 0; i < recordCount; i++) {
cursor.moveToNext();
int id = cursor.getInt(0);
String name = cursor.getString(1);
int age = cursor.getInt(2);
String mobile = cursor.getString(3);
printText("레코드#"+ i + " : " + id + ", " + name + ", " + age + ", " + mobile);
}
cursor.close();
}
[ API ]
칼럼에 대한 정보를 알아낼 수 있는 메서드
- public abstract int getColumncount () : 칼럼의 전체 개수
- public abstract int getColumnIndex (String columnName) : 칼럼의 이름을 통해 칼럼의 인덱스 확인
- public abstract String getColumnName (int columnIndex) : 칼럼의 인텍스를 통해 칼럼의 이름을 확인
- public abstract String[] getColumnNames ()
Cursor 관련 메서드
- public abstract int getCount() : 레코드 개수
- public abatract boolean moveToNext() : Cursor를 다음으로 이동
- public abatract boolean moveToPrevious() : Cursor를 이전으로 이동
- public abatract boolean moveToFirst() : Cursor를 맨 처음으로 이동
- public abatract boolean moveToLast() : Cursor를 맨 마지막으로 이동
- public abatract boolean move (int offset) : offset만큼 Cursor를 이동(음수는 이전, 양수는 다음으로)
⭐ 기억해야 할 순서!
(1) 데이터베이스 생성 → (2) 테이블 생성 → (3) 레코드 추가 → (3) 데이터 조회
다음 포스팅에서는 내용 제공자를 이용한 데이터 생성, 조회, 수정, 삭제에 대해 다루겠습니다!
* SharedPreferences에 대한 자세한 내용은 아래 포스팅 참고!