: 클라이언트 어플리케이션에 주로 사용하는 경량 내장형 DBMS
; 모바일 기기의 APP의 데이터를 기기 내에 DB를 이용하여 저장해야 할 때 주로 사용된다. (다른 사람과 공유해야하는 데이터는 이거말고 외부 서버를 이용)
사용 과정
1. DB설계
: 요구사항, UI등을 고려하여 테이블을 설계
2. Helper 클래스 작성
: SQLiteOpenHelper를 상속받아 설계를 바탕으로 DB 테이블을 생성
// SQLiteOpenHelper는 package를 import하여 사용가능
// 테이블 생성 후 샘플 데이터를 추가할 수도 있다.
3. DB 사용
: DB에 접근이 필요할 때 Helper클래스 객체를 생성하여 DB를 사용할 수 있다.
// 객체를 생성할 때 용도를 지정할 수 있다. (Writable/Readable)
+) 필요에 따라 DTO, DAO등을 추가로 개발하여 사용가능하다.
DTO(Data Transfer Object) 데이터 전송 객체
DAO(Data Access Object) 데이터 접근 객체
< 연락처 관리 어플 >
기능1. 연락처 분류 가능 : 친구 / 가족 / 기타
기능2. 이름으로 검색 가능
CREATE TABLE contact_table (_id integer primary key autoincrement,
name TEXT, phone TEXT, category TEXT)
SQLiteOpenHelper
: 안드로이드 DB를 편리하게 사용할 수 있도록 도와주는 클래스
생성자 추가
: 사용할 DB 파일 명 및 DB 버전을 지정한다.
onCreate()/onUpgrade()재정의는 필수
onCreate() : 사용할 테이블을 SQL을 사용하여 생성한다.
onUpgrade() : 테이블 구조를 변경해야 할 필요가 있을 때 사용한다. 재정의하지 않아도 무방하긴 하다.
Android Studio에서 Device File Explorer 에서 확인 가능 (eclipse에서는 DDMS로 화면 전환 후 File Explorer 선택)
또는
DB파일을 컴퓨터에 저장한 후 SQLiteBrowser를 통한 확인도 가능
+) 실기기에서는 보안 문제로 폴더 외부 접근이 안되므로 에뮬레이터 상에서만 확인 가능하다.
package mobile.example.dbtest;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class ContactDBHelper extends SQLiteOpenHelper {
private final String TAG = "ContactDBHelper";
private final static String DB_NAME = "contact_db";
public final static String TABLE_NAME = "contact_table";
public final static String COL_NAME = "name";
public final static String COL_PHONE = "phone";
public final static String COL_CAT = "category";
public ContactDBHelper(Context context) {
super(context, DB_NAME, null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
String createSql = "create table " + TABLE_NAME + " ( _id integer primary key autoincrement,"
+ COL_NAME + " TEXT, " + COL_PHONE + " TEXT, " + COL_CAT + " TEXT);";
Log.d(TAG, createSql);
db.execSQL(createSql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
}
private final static String DB_NAME = "contact_db";
public final static String TABLE_NAME = "contact_table";
public final static String COL_NAME = "name";
public final static String COL_PHONE = "phone";
public final static String COL_CAT = "category";
: 테이블명, 컬럼 명 등을 상수로 선언하여 수정이 용이하게 함.
public ContactDBHelper(Context context) {
super(context, DB_NAME, null, 1);
}
: 생성자 선언 (DB파일 생성!)
; super()를 호출하여 생성할 DB파일을 지정
@Override
public void onCreate(SQLiteDatabase db) {
String createSql = "create table " + TABLE_NAME + " ( _id integer primary key autoincrement,"
+ COL_NAME + " TEXT, " + COL_PHONE + " TEXT, " + COL_CAT + " TEXT);";
Log.d(TAG, createSql);
db.execSQL(createSql);
}
: onCreate 메소드 재정의 (DB Table 생성!)
; 상수값을 가져다 sql문을 만든다.
; Log를 사용한 디버깅으로 결과확인
; onCreate 메소드는 첫 호출 이후에는 호출되지 않음. 그러므로 수정 후에는 앱을 기기에서 지우고 다시 실행해야함.
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
: onUpgrade 메소드 재정의
; DB버전이 변경된 경우 사용된다.
; DB를 제거하고 다시 onCreate하는 역할도 포함한다.
1. helper 객체 생성
: DB클래스는 helper클래스에 의해 관리된다.
helper는 생성한 테이블을 보유하고 테이블 관련 query를 수행할 수 있다.
ContactDBHelper helper = new ContactDBHelper(this)
2. helper를 사용하여 SQLiteDatabase객체 획득
: help에서 해당 객체를 가져와 DB작업 수행
//읽기쓰기가능
SQLiteDatabase myDB = helper.getWritableDatabase()
or
//읽기가능
SQLiteDatabase myDB = helper.getReadableDatabase()
3. SQLiteDatabase 객체를 사용하여 Query 수행
: DB객체 획득 후 SQL을 직접 사용하거나 관련 메소드를 사용하여 query 수행
//CRUD 데이터 기본연산 메소드
myDB.insert() // = create
myDB.update()
myDB.delete()
myDB.query() // = select(read)
or
//SQL 연산
myDB.execSQL() //insert, update, delete 기능
myDB.rawQuery() // select 기능, Cursor 사용
4. helper 객체(및 관련 객체) Close 수행
: close하지 않으면 데이터 커밋이 안 일어날 수도 있음
helper.close()
Query에는 전용 메소드를 사용하는 방식과 SQL문을 사용하는 방식이 있다.
방법1. insert()
: ContentValues 객체 생성 후 입력할 데이터 값을 설정한 다음 insert()
ContentValues row = new ContentValues();
row.put("name", "컴퓨터");
row.put("phone", "1234");
row.put("category", "정보과학대학");
db.insert("contact_table, null, row);
방법2. execSQL()
db.execSQL("INSERT INTO contact_table VALUES (NULL, '컴퓨터', '1234', '정보과학대학');");
방법1. update()
ContentValues row = new ContentValues();
row.put("phone", "0123");
String whereClause = "name=?" //clause 절
String[] whereArgs = new String[]{"컴퓨터"};
db.update("contact_table", row, whereClause, whwerArgs);
put(수정할 컬럼명, 수정할 값)
whereClause가 수정할 값이 있는 레코드를 지정할 수 있는 조건column을 제시함. (null이 오면 전체 행 삭제를 의미)
whereArgs에는 whereClause에서 지목한 필드의 값을 입력
update(table명, ContentValues, 조건, 조건 값 배열)
+) whereClause에 name=? and phone=? 이 오면 whereArgs의 배열에는 값을 2개 넣으면 된다.
방법2. execSQL()
db.execSQL("UPDATE contact_table SET phone = '0123' WHERE name = '컴퓨터';");
방법1. delete()
String whereClause = "name=?";
String[] whereArgs = new String[]{"컴퓨터"};
db.delete("contact_table", whereClause, whereArgs);
방법2. execSQL()
db.execSQL("DELETE FROM contact_table WHERE name = '컴퓨터';");
방법1. query() (메소드 사용)
String[] columns = {"_id", "name", "phone", "category"};
String selection = "name=?";
String[] selectArgs = new String[] {"컴퓨터"};
Cursor cursor = db.query("contact_table", columns,
selection, selectArgs, null, null, null, null);
방법2. rawQuery() (SQL사용)
Cursor cursor = db.rawQuery("SELECT _id, name, phone, category
FROM contact_table WHERE name = '컴퓨터';", null);
또는
Cursor cursor = db.rawQuery("SELECT * FROM contact_table
WHERE name = ?;", new String[] {"컴퓨터"}););
: select문에 의해 반환한 레코드의 집합을 지정한다.
moveToNext()
: 이동할 레코드가 있으면 true, 없으면 false를 반환
Cursor는 데이터 반환 집합에 대한 레퍼런스다.
: get타입을 사용하여 값을 읽어온다. (읽어온 값은 cloumn순서)
Cursor는 사용 후 close() 해줘야 한다.
ex.
String result = "";
while (cursor.moveToNext()) {
int id = cursor.getInt(0);
String name = cursor.getString(1);
String phone = cursor.getString(2);
String category = cursor.getString(3);
result += category + ":" + name + "-" + phone + "\n";
//여기에 DTO나 list가 들어간다
}
cursor.close();
// cursor.get타입(column순서)보다 cursor.getColumnIndex(컬럼명)이 권장된다.
Data Transfer Object로 서로 다른 layer에 정보를 주고 받는 용도로 정의한 클래스.
package mobile.example.dbtest;
import java.io.Serializable;
public class ContactDto implements Serializable {
private long id;
private String name;
private String phone;
private String category;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
@Override
public String toString() {
return id + ". " + category + " - " + name + " (" + phone + ")";
}
}
public class ContactDto implements Serializable에서
implements Serializable를 하면 이 객체 자체를 intent에도 담을 수 있고, Serializable의 기능이 제공되는 곳에 이 DTO를 전달할 수 있다.
: ListView에 연결할 ArrayAdapter 또는 커스텀 Adapter에 ArrayList<아이템> 형태의 배열을 전달한다.
; 연결 시 새로운 데이터의 입력, 수정, 삭제에 따른 문제가 발생한다.
따라서 DB를 갱신할 경우 ArrayList의 갱신도 필수.
@Override
protected void onResume() { //resume 재개하다
super.onResume();
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from " +
ContactDBHelper.TABLE_NAME, null);
contactList.clear();
while(cursor.moveToNext()) {
ContactDto dto = new ContactDto();
dto.setId(cursor.getInt(cursor.getColumnIndex("_id")));
dto.setName((cursor.getString(cursor.getColumnIndex(ContactDBHelper.COL_NAME))));
dto.setPhone(cursor.getString(cursor.getColumnIndex(ContactDBHelper.COL_PHONE)));
dto.setCategory(cursor.getString(cursor.getColumnIndex(ContactDBHelper.COL_CAT)));
contactList.add(dto);
}
adapter.notifyDataSetChanged();
cursor.close();
helper.close();
}
contactList.clear();
clear 해주지 않으면 앱을 켤 때마다 동일한 내용이 ListView에 담긴다.
Cursor cursor = db.rawQuery("select * from " +
ContactDBHelper.TABLE_NAME, null);
위 코드는 sql을 직접 작성한 경우이다.
메소드를 사용하여 작성할 수도 있다. ↓
Cursor cursor = db.query(ContactDBHelper.TABLE_NAME, null,
null, null, null, null, null, null);
while(cursor.moveToNext()) {
ContactDto dto = new ContactDto();
dto.setId(cursor.getInt(cursor.getColumnIndex("_id")));
dto.setName((cursor.getString(cursor.getColumnIndex(ContactDBHelper.COL_NAME))));
dto.setPhone(cursor.getString(cursor.getColumnIndex(ContactDBHelper.COL_PHONE)));
dto.setCategory(cursor.getString(cursor.getColumnIndex(ContactDBHelper.COL_CAT)));
contactList.add(dto);
}
DTO객체 생성 후 읽어온 데이터의 각 컬럼에 해당하는 값을 저장 후 contactList(ArrayList)에 추가.
adapter.notifyDataSetChanged();
DB의 내용으로 갱신한 contactList(ArrayList)의 내용을 ListView에 반영하기 위해 호출.
: Click 또는 LongClick시 pos 매개변수를 사용하여 contactList에서 해당 위치의 DTO 객체 추출
ListView에서 ArrayList를 이용할 땐 pos를 사용하고 DB를 이용할 땐 추출한 id를 이용한다.
AdapterView.OnItemClickListener itemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
//id를 사용하여 DB 접근
}
};
AdapterView.OnItemLongClickListener itemLongClickListener = new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClickListener(AdapterView<?> parent, View view, int pos, long id) {
//id를 사용하여 DB 접근
return false;
}
};