출처: https://cocomo.tistory.com/409
https://soulduse.tistory.com/21
위의 링크들을 보면서 내 프로젝트에서도 SQLite 데이터베이스 사용을 해보았다.
1. 데이터베이스 관리 객체
public class LogDB extends SQLiteOpenHelper { // 싱글톤 구현 private static LogDB db = null; private LogDB(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } public static LogDB getDB(Context context) { if (db == null) db = new LogDB(context, "TRAVELLOG", null, 1); return db; } // 데이터베이스 생성 @Override public void onCreate(SQLiteDatabase db) { StringBuffer sb = new StringBuffer(); sb.append("create table if not exists ROUTE ("); sb.append("ID integer primary key autoincrement, "); sb.append("ITINERARY text not null, "); sb.append("LATITUDE real not null, "); sb.append("LONGITUDE real not null, "); sb.append("MEMO text, "); sb.append("IMAGE BLOB)"); db.execSQL(sb.toString()); Log.e("DB: ", "Success"); } // 데이터베이스 버전 업그레이드 @Override public void onUpgrade(SQLiteDatabase db, int i, int i1) { } // 레코드 추가 public void insert(PlaceInfo placeInfo) { SQLiteDatabase db = getWritableDatabase(); StringBuffer sb = new StringBuffer(); sb.append("insert into ROUTE ("); sb.append("ITINERARY, LATITUDE, LONGITUDE, MEMO, IMAGE )"); sb.append("values (?, ?, ?, ?, ?)"); db.execSQL(sb.toString(), new Object[]{ placeInfo.getItinerary(), placeInfo.getLatitude(), placeInfo.getLongitude(), placeInfo.getMemo(), placeInfo.getImage() }); Log.e("Insert: ", "Success"); } // 레코드 수정 public void update(PlaceInfo placeInfo) { SQLiteDatabase db = getWritableDatabase(); StringBuffer sb = new StringBuffer(); sb.append("update ROUTE set "); sb.append("ITINERARY = ?, "); sb.append("LATITUDE = ?, "); sb.append("LONGITUDE = ?, "); sb.append("MEMO = ?, "); sb.append("IMAGE = ? "); sb.append("where ID = ?"); db.execSQL(sb.toString(), new Object[]{ placeInfo.getItinerary(), placeInfo.getLatitude(), placeInfo.getLongitude(), placeInfo.getMemo(), placeInfo.getImage(), placeInfo.getId() }); Log.e("Update: ", "Success"); } // 레코드 삭제 public void delete(PlaceInfo placeInfo) { SQLiteDatabase db = getWritableDatabase(); StringBuffer sb = new StringBuffer(); sb.append("delete from ROUTE "); sb.append("where id = ?"); db.execSQL(sb.toString(), new Object[]{ placeInfo.getId() }); Log.e("Delete: ", "Success"); } // 여정표 레코드들 조회 public ArrayList getRouteList(String itinerary) { SQLiteDatabase db = getReadableDatabase(); StringBuffer sb = new StringBuffer(); ArrayList placeInfoList = new ArrayList(); sb.append("select ID, ITINERARY, LATITUDE, LONGITUDE, MEMO, IMAGE "); sb.append("from ROUTE "); sb.append("where ITINERARY like ? "); sb.append("order by ID"); Cursor cursor = db.rawQuery(sb.toString(), new String[]{ itinerary }); while (cursor.moveToNext()) { PlaceInfo placeInfo = new PlaceInfo(); placeInfo.setId(cursor.getInt(0)); placeInfo.setItinerary(cursor.getString(1)); placeInfo.setLatitude(cursor.getDouble(2)); placeInfo.setLongitude(cursor.getDouble(3)); placeInfo.setMemo(cursor.getString(4)); placeInfo.setImage(cursor.getBlob(5)); placeInfoList.add(placeInfo); } Log.e("SelectAll: ", "Success"); return placeInfoList; } // 여정표 이름 조회 public ArrayList getRouteListName() { SQLiteDatabase db = getReadableDatabase(); StringBuffer sb = new StringBuffer(); ArrayList itineraryList = new ArrayList(); sb.append("select ITINERARY "); sb.append("from ROUTE "); sb.append("group by ITINERARY "); sb.append("order by ID desc"); Cursor cursor = db.rawQuery(sb.toString(), null); while (cursor.moveToNext()) { itineraryList.add(cursor.getString(0)); } Log.e("SelectName: ", "Success"); return itineraryList; } }
2. 데이터베이스 레코드 객체
public class PlaceInfo { private int id; private String itinerary; private double latitude; private double longitude; private String memo; private byte[] image; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getItinerary() { return itinerary; } public void setItinerary(String itinerary) { this.itinerary = itinerary; } public double getLatitude() { return latitude; } public void setLatitude(double latitude) { this.latitude = latitude; } public double getLongitude() { return longitude; } public void setLongitude(double longitude) { this.longitude = longitude; } public String getMemo() { return memo; } public void setMemo(String memo) { this.memo = memo; } public byte[] getImage() { return image; } public void setImage(byte[] image) { this.image = image; } }
1. 데이터베이스 관리 객체 싱글톤 구현
- DB 관리 객체를 하나만 만들어서 그것만 계속 쓰게 한다.
뭐 조금 생각해보면 이런 녀석이 많이 있다는 게 더 이상하긴 하다.
저기서 context 변수는 이 인스턴스를 쓰려는 Activity이다.
출처: https://jeong-pro.tistory.com/86
2. onCreate()
- 데이터베이스에 테이블이 없는 경우 한 번만 호출되어 테이블을 생성한다.
StringBuffer를 사용했는데, 그 이유는 String보다 빠르게 처리하는데 좋다고 한다.
그리고 execSQL()을 이용하여 SQL 명령어를 실행한다.
3. onUpgrade()
- 데이터베이스 버전이 올라갈 때 호출
따로 구현은 하지 않았다.
3. Insert, Update, Delete
- 우선 데이터베이스를 쓰기(Write) 위한 상태로 만든다.
이것은 getWritableDatabase() 메소드로 한다.
그리고 StringBuffer와 execSQL() 설명은 위와 동일하다.
다만 조건을 위해 추가되는 특정 필드값은 SQL 명령어에서는 ?로 한 다음,
execSQL() 메서드에 Object 배열을 매개변수에 추가했다.
4. Select
- 데이터베이스를 읽기 위한 상태로 만든다.
이는 getReadableDatabase() 메소드로 한다.
그리고 cursor란 것을 받아오는데, 워드에서 쓰던 그 커서랑 같은 녀석이다.
cursor를 받기 위해 rawQuery() 메소드를 사용했는데,
특정 필드값을 ? 처리 후 Object 배열 매개변수를 추가한다는 점에서
execSQL()과 비슷하다.
이 cursor는 레코드 단위로 움직이면서 읽을 레코드가 있을 때까지(moveToNext() 메소드)
레코드 내 필드값들을 getXXX() 메소드로 가져온다.
그리고 읽어온 레코드들을 List에 저장 후 return 값으로 보냈다.
5. 데이터베이스 레코드 객체
- 캡슐화를 위해 변수는 private 선언 후
getter와 setter로 접근 및 설정을 하도록 했다.
앞으로도 이런 거 계속 쓸 건데 잊지 않도록 해야겠다.