반응형



Android에서 SQLite를 사용하여 테이블 생성시 문제가 생겼던 점을 포스팅합니다.

SQLiteOpenHelper를 상속받은 클래스를 사용하여 데이터베이스 파일을 관리하지 않으면 생길 수 있는 상황인 듯합니다.




다음과 같은 구조의 테이블을 사용하여 앱을 만들다가


레코드이름

타입

id

integer

image

blob

text

text



기존 테이블을 삭제하고 날짜 레코드를 추가했습니다.  

문제 없이 동작하는 듯했습니다.


레코드이름

타입

id

integer

image

blob

text

text

date

date




앱을 새로 설치할때 문제가 없는지 테스트해보다가 버그(?)를 찾았네요.

분명 date 타입이 추가된 테이블을 새로 생성하도록 했는데 date가 없는 테이블이 데이터베이스에 있다고 에러가 났습니다.

확인해보니 데이블을 생성하기 전에 기존 테이블을 삭제해야 에러가 안나더군요.


앱이 최초 실행될 때에만 기존 테이블이 있는 경우 삭제해주면 해결되는 상황이었습니다.

그래서 대부분의 앱들이 재설치시 기존 데이터가 날라간다고 하나봅니다.


알고보니 앱을 삭제해도 SQLite에서 생성한 데이터베이스 파일은 남는다는 군요.

안드로이드 스튜디오에서 설치하는 과정에서도 데이터베이스 파일이 남는 듯합니다.



SQLiteOpenHelper를 상속받은 클래스를 사용해서 해결했습니다.

앱이 새로 설치된 후에만 이 클래스의 onCreate 메소드에서 테이블을 생성하더군요.


안드로이드 스튜디오에서 설치를 다시 하거나 apk 파일로 만들어서 설치를 다시 진행해도 새로 생성하지 않습니다.

기존에 있던 테이블을 그대로 사용합니다.  플레이스토어에서 다운받아 설치하면 어떨지는 테스트 못해봤습니다.




사용한 SQLiteOpenHelper를 상속받은 클래스와 MainActivity에서 사용하는 방법을 남겨둡니다.


기존에 사용하던 코드입니다.

db = openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null);


// db.insert, db.execSQL, db.rawQuery


db.close();



다음처럼 변경해서 사용했습니다.


1. 다음 2개의 변수를 선언합니다.


SQLiteHelper mSQLiteHelper;
SQLiteDatabase mDb;


2. onCreate 메소드에서 SQLiteHelper 객체를 생성합니다.


mSQLiteHelper = new SQLiteHelper(this);



3. DB에서 읽어올때 다음처럼 합니다.

mDb = mSQLiteHelper.getReadableDatabase();

// db.execSQL, db.rawQuery

mDb.close();




4. DB에 쓸 때 다음처럼 합니다.


mDb = mSQLiteHelper.getWritableDatabase();

// db.insert, db.execSQL, db.rawQuery

mDb.close();




SQLiteHelper .java


테이블에 새로운 레코드를 추가시 기존 데이터는 남겨두고 할 수 있는 방법은 아직 테스트 못했습니다.

주석한 부분을 참고하여 진행하면 될듯합니다.


package com.tistory.webnautes.imagesaveinsqlite;


import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class SQLiteHelper extends SQLiteOpenHelper {


   // 데이터베이스
   private static final String DATABASE_NAME      = "test.db";
   private static final int DATABASE_VERSION      = 1;

   // 테이블
   public static final String TABLE_NAME       = "imageTb";
   public static final String COLUMN_ID        = "id";
   public static final String COLUMN_DATE      = "date1";
   public static final String COLUMN_FEEL      = "feels";
   public static final String COLUMN_IMAGE     = "image";
   public static final String COLUMN_TEXT      = "text";

   private static final String DATABASE_CREATE_TEAM = "create table "
           + TABLE_NAME + "(" + COLUMN_ID + " integer primary key autoincrement, "
           + COLUMN_DATE + " date, "
           + COLUMN_FEEL + " integer, "
           + COLUMN_IMAGE + " blob, "
           + COLUMN_TEXT + " text);";


// 기존 테이블에 레코드 추가시 사용
//    private static final String DATABASE_ALTER_TEAM_1 = "ALTER TABLE "
//            + TABLE_TEAM + " ADD COLUMN " + COLUMN_COACH + " string;";
//
//    private static final String DATABASE_ALTER_TEAM_2 = "ALTER TABLE "
//            + TABLE_TEAM + " ADD COLUMN " + COLUMN_STADIUM + " string;";


   public SQLiteHelper(Context context) {
       super(context, DATABASE_NAME, null, DATABASE_VERSION);
   }


   @Override
   public void onCreate(SQLiteDatabase db) {
       // 앱을 삭제후 앱을 재설치하면 기존 DB파일은 앱 삭제시 지워지지 않기 때문에
       // 테이블이 이미 있다고 생성 에러남
       // 앱을 재설치시 데이터베이스를 삭제해줘야함.
       db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
       db.execSQL(DATABASE_CREATE_TEAM);
   }


   @Override
   public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

       db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
       onCreate(db);

         //기존 테이블에 레코드 추가시 사용
//        if (oldVersion < 2) {
//            db.execSQL(DATABASE_ALTER_TEAM_1);
//        }
//        if (oldVersion < 3) {
//            db.execSQL(DATABASE_ALTER_TEAM_2);
//        }
   }


}





참고


https://thebhwgroup.com/blog/how-android-sqlite-onupgrade




최초 작성 2019. 2. 28




반응형

문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.

도움이 되셨다면 토스아이디로 후원해주세요.
https://toss.me/momo2024


제가 쓴 책도 한번 검토해보세요 ^^

+ Recent posts