SQLiteOpenHelper onCreate () / onUpgrade ()는 언제 실행됩니까?


293

나는 내 테이블을 SQLiteOpenHelper onCreate()만들었지 만

SQLiteException: no such table

또는

SQLiteException: no such column

오류. 왜?

노트:

(매주 수십 개의 유사한 질문이 요약되어 있습니다. 여기에서 "정식"커뮤니티 위키 질문 / 답변을 제공하려고 시도하면 모든 질문에 대한 올바른 참조가 가능합니다.)


12
@ Ndupza 이것은 실제 문제가 아니며 N 번째로 동일한 답변 / 의견을 작성하는 데 지쳤습니다.
laalto

답변:


352

SQLiteOpenHelper onCreate()onUpgrade()데이터베이스가 실제로 호출에 의해, 예를 들어, 열 때 콜백이 호출됩니다 getWritableDatabase(). 데이터베이스 헬퍼 오브젝트 자체가 작성 될 때 데이터베이스가 열리지 않습니다.

SQLiteOpenHelper데이터베이스 파일 버전. 버전 번호는 생성자에int 전달 된 인수 입니다. 데이터베이스 파일에서 버전 번호는에 저장됩니다 .PRAGMA user_version

onCreate()데이터베이스 파일이 존재하지 않고 방금 작성된 경우에만 실행됩니다. onCreate()성공적으로 반환 되면 (예외가 발생하지 않음) 요청 된 버전 번호로 데이터베이스가 생성 된 것으로 간주됩니다. 함의로서, 당신은 잡을 안 SQLException에들 onCreate()자신.

onUpgrade()데이터베이스 파일이 존재하지만 저장된 버전 번호가 생성자에서 요청한 것보다 낮은 경우에만 호출됩니다. 는 onUpgrade()요청 된 버전으로 테이블 스키마를 업데이트해야합니다.

코드 ( onCreate()) 에서 테이블 스키마를 변경할 때 데이터베이스가 업데이트되었는지 확인해야합니다. 두 가지 주요 접근법 :

  1. 이전 데이터베이스 파일을 삭제하여 onCreate()다시 실행하십시오. 설치된 버전을 제어하고 데이터 손실이 문제가되지 않는 개발 시간에 종종 선호됩니다. 데이터베이스 파일을 삭제하는 몇 가지 방법 :

    • 응용 프로그램을 제거하십시오. 응용 프로그램 관리자 또는 adb uninstall your.package.name쉘에서 사용하십시오 .

    • 응용 프로그램 데이터를 지 웁니다. 응용 프로그램 관리자를 사용하십시오.

  2. onUpgrade()호출 되도록 데이터베이스 버전을 늘리십시오. 더 많은 코드가 필요할수록 약간 더 복잡합니다.

    • 데이터 손실이 문제가되지 않는 개발 시간 스키마 업그레이드의 경우 execSQL("DROP TABLE IF EXISTS <tablename>")기존 테이블을 제거 onCreate()하고 데이터베이스를 재생성하기 위해 호출 할 수 있습니다.

    • 릴리스 된 버전의 경우 onUpgrade()사용자가 데이터를 잃지 않도록 데이터 마이그레이션을 구현해야 합니다.


2
@Laalto // onUpgrade ()의 데이터 마이그레이션 // 이에 대해 설명해 주시겠습니까?
bCliks

2
@bala이 질문 / 답변의 범위에 있지 않습니다. 질문이 있으시면 언제든지 질문으로 게시하십시오.
laalto

2
@Jaskey 버전 번호는 코드의 코드 번호입니다. 파일이 이전 버전 (앱의 이전 버전) 인 경우 파일을 업그레이드해야합니다.
laalto

4
따라서 스키마를 수정할 때마다 SQLiteHelper에서 DB VERSION을 하드 코딩해야합니다. 따라서 이전 앱이 실행되고 db 연결이 얻어지고 오래된 것을 발견하면 onCreate 대신에 onUpgrade가 중단됩니다. 권리?
Jaskey

2
감사합니다 ! 이것은 나에게 의미가 있습니다. 잘 이해하고 있는지 확인하십시오. 따라서 스키마를 업데이트 할 때마다 1. DB_VERSION 변수 (하드 코드)를 수정하십시오. 2.에서 onUpdate()모든 이전 버전을 확인하고 적절한 데이터 마이그레이션을 수행하십시오. 그런 다음 사용자가 앱을 업데이트하면 (이전의 db 파일 onUpgrade이 있음) 트리거되고 사용자가 새로 설치되면 onCreate()트리거됩니다.
Jaskey

97

Jaskey의 요청에 따라 여기에 누락 된 포인트를 추가하려면

데이터베이스 버전은 SQLite데이터베이스 파일 내에 저장 됩니다.

catch는 생성자입니다

SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

따라서 데이터베이스 도우미 생성자가 name(두 번째 매개 변수) 로 호출 되면 플랫폼은 데이터베이스가 존재하는지 여부를 확인하고 데이터베이스가 존재하면 데이터베이스 파일 헤더에서 버전 정보를 가져와 올바른 콜백을 트리거합니다.

이전 답변에서 이미 설명했듯이 이름의 데이터베이스가 존재하지 않으면 트리거됩니다 onCreate.

아래 설명은 onUpgrade사례와 함께 사례를 설명합니다 .

예를 들어 첫 번째 버전의 응용 프로그램에는 생성자 전달 버전 이 DatabaseHelper(extending SQLiteOpenHelper) 1이고 버전이 다음과 같은 새 소스 코드로 업그레이드 된 응용 프로그램을 제공 한 2다음 파일이 이미 DatabaseHelper생성되어 플랫폼 트리거 onUpgrade가 발생하면 파일이 이미 존재 하는지 확인합니다. 그러나 버전이 전달한 현재 버전보다 낮습니다.

이제 db 버전으로 응용 프로그램의 세 번째 버전을 제공 할 계획이라고 가정합니다 3(데이터베이스 스키마가 수정 될 때만 db 버전이 증가 함). 이러한 증분 업그레이드에서는 유지 관리하기 쉬운 코드를 위해 각 버전에서 업그레이드 논리를 증분 작성해야합니다.

아래의 의사 코드 예 :

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  switch(oldVersion) {
    case 1:
       //upgrade logic from version 1 to 2
    case 2:
       //upgrade logic from version 2 to 3
    case 3:
       //upgrade logic from version 3 to 4
       break;
    default:
       throw new IllegalStateException(
                "onUpgrade() with unknown oldVersion " + oldVersion);
  }
}

break경우 1및 누락 된 문을 확인하십시오 2. 이것이 증분 업그레이드의 의미입니다.

이전 버전 인 경우 말 2새로운 버전이 4다음 논리에서 데이터베이스를 업그레이드합니다 23다음에4

이전 버전 인 경우 3새로운 버전이 4, 그것은 단지에 대한 업그레이드 논리 실행 3에를4


1
스위치 (newVersion)를 대신 switch (oldVersion)로 사용하고 싶다고 생각합니다. newVersion이 4인지 (5 또는 3이 아님, 논리가 새 버전이 4라고 가정하기 때문에) 확인하고 싶을 수도 있습니다. 이전 버전이 2이고 새 버전이 5이면 사례 4를 수행하고 3에서 4로 업그레이드하십시오 (아마도 예상되는 동작이 아님).
joe p

오른쪽-오타 .. 그러나 새 버전이 5-> 인 경우 항상 IllegalStateException이 발생하고 개발자는 사례 5를 추가하여 문제를 해결합니다.
Aun

1
사용자가 앱을 버전 2에서 3으로 만 업그레이드하면 어떻게 되나요? 이 경우에도 사례 4까지의 모든 사례가 실행됩니다.
Paramvir Singh

6
@param 사용자는 그렇게 할 수 없습니다. 그는 2를 최신 (여기서는 4)으로 만 업그레이드 할 수 있습니다.
Habeeb Perwad

20

onCreate()

  1. 데이터베이스를 처음 만들 때 (즉, 데이터베이스가 존재하지 않는 경우) onCreate()전달 된 버전으로 데이터베이스를 만듭니다. SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

  2. onCreate()메소드는 정의한 테이블을 작성하고 작성한 다른 코드를 실행하는 것입니다. 그러나이 메서드는 앱의 데이터 디렉토리 ( /data/data/your.apps.classpath/databases) 에 SQLite 파일이없는 경우에만 호출됩니다 .

  3. 코드를 변경하고 에뮬레이터에서 다시 시작한 경우에는이 메소드가 호출되지 않습니다. 당신이 원하는 경우 onCreate()실행할 수는 SQLite 데이터베이스 파일을 삭제 ADB를 사용해야합니다.

onUpgrade()

  1. SQLiteOpenHelper 수퍼 생성자를 호출해야합니다.
  2. onUpgrade()방법은 버전 정수가 앱에서 실행중인 현재 버전보다 큰 경우에만 호출됩니다.
  3. 당신이 원하는 경우 onUpgrade()메소드를 호출 할, 당신은 당신의 코드에서 버전 번호를 증가해야합니다.

1
제공하는 솔루션에 대한 설명을 조금 더 추가하여 답변을 더 자세히 설명해 주시겠습니까?
abarisone 2016 년

10

너무 늦었을 수도 있지만 짧고 달콤한 답변을 공유하고 싶습니다. 같은 문제에 대한 답변 을 확인하십시오 . 확실히 당신을 도울 것입니다. 더 이상 깊은 사양이 없습니다.

테이블 생성 구문에 대해 확신이있는 경우 동일한 테이블에 새 열을 추가 할 때 발생할 수있는 것보다 ...

1) 장치에서 제거하고 다시 실행하십시오.

또는

2) 설정-> 앱-> ClearData

또는

3)DATABASE_VERSION "DatabaseHandler"클래스 변경 (새 열을 추가 한 경우 자동으로 업그레이드되는 것보다)

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

또는

4)DATABASE_NAME "DatabaseHandler"클래스의 변경 (같은 문제에 직면했지만 변경하여 성공합니다 DATABASE_NAME.)


내 DB가 있고 SQLiteAssetHelper 클래스를 사용하고 있습니다. 그래서 전에 sql 스크립트로 DB를 만들었고 db를 만들었습니다. SQLiteAssetHelper를 사용하면 에뮬레이터 또는 장치에서 동일한 버전의 DB이기 때문에 앱을 제거 할 때까지 DB를 복사 할 수 없었습니다.
Behzad

4

확장 할 때 기억해야 할 사항 SQLiteOpenHelper

  1. super(context, DBName, null, DBversion); -생성자의 첫 줄을 호출해야합니다.
  2. 무시 onCreate하고onUpgrade (필요한 경우)
  3. onCreate경우에만 호출됩니다 getWritableDatabase()또는 getReadableDatabase()실행됩니다. 그리고이 때 한 번만 호출됩니다DBName 첫 번째 단계에서 지정된 것을 사용할 수 없을 . onCreate메소드에 테이블 작성 쿼리를 추가 할 수 있습니다.
  4. 새 테이블을 추가 할 때마다 테이블 DBversion에서 쿼리를 변경 하고 수행 onUpgrade하거나 단순히 앱을 제거한 다음 설치하십시오.

3

onCreate테이블 작성이 필요한 경우 처음으로 가 호출됩니다. SQLiteDatabase에 의해 실행되는 테이블 작성을위한 스크립트를 작성하는 경우이 메소드를 대체해야합니다. execSQL 방법. 최초 배포에서 실행 한 후에는이 메서드가 호출되지 않습니다.

onUpgrade 이 메소드는 데이터베이스 버전이 업그레이드 될 때 호출됩니다. 첫 번째 배포의 경우 데이터베이스 버전이 1이고 두 번째 배포의 경우 테이블에 열을 추가하는 것과 같은 데이터베이스 구조가 변경되었다고 가정합니다. 데이터베이스 버전이 2라고 가정하십시오.


2

당신은 같은 데이터베이스 및 테이블을 만들 수 있습니다

public class DbHelper extends SQLiteOpenHelper {
private static final String DBNAME = "testdatbase.db";
private static final int VERSION = 1;

public DbHelper(Context context) {
    super(context, DBNAME, null, VERSION);
    // TODO Auto-generated constructor stub
}

@Override
public void onCreate(SQLiteDatabase db) {
    // TODO Auto-generated method stub
    db.execSQL("create table BookDb(id integer primary key autoincrement,BookName text,Author text,IssuedOn text,DueDate text,Fine text,Totalfine text");

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS BookDb");
    onCreate(db);
  }
}

참고 : 다른 테이블을 만들거나 열을 추가하거나 그러한 테이블을 추가하지 않으려면 VERSION을 늘리십시오.


2

Sqlite 데이터베이스는 두 가지 방법을 재정의

1) onCreate () :이 메소드는 애플리케이션이 처음 시작될 때 한 번만 호출됩니다. 한 번만 호출

2) onUpgrade ()이 메소드는 데이터베이스 버전을 변경할 때 호출 된 다음이 메소드가 호출됩니다.이 메소드는 DB 스키마를 생성 한 후 새 열 추가와 같은 테이블 구조를 변경하는 데 사용됩니다.


1

이러한 테이블을 찾지 못하면 주로 SQLiteOpenHelper클래스를 열지 않았을 때 getwritabledata()데이터베이스 이름 및 버전의 make 생성자를 호출해야합니다. 그리고 클래스에 OnUpgrade주어진 버전 번호에 업그레이드 값이있을 때마다 호출 SQLiteOpenHelper됩니다.

아래는 코드 스 니펫입니다 (열 이름에 철자가 없기 때문에 해당 열을 찾을 수 없습니다).

public class database_db {
    entry_data endb;
    String file_name="Record.db";
    SQLiteDatabase sq;
    public database_db(Context c)
    {
        endb=new entry_data(c, file_name, null, 8);
    }
    public database_db open()
    {
        sq=endb.getWritableDatabase();
        return this;
    }
    public Cursor getdata(String table)
    {
        return sq.query(table, null, null, null, null, null, null);
    }
    public long insert_data(String table,ContentValues value)
    {
        return sq.insert(table, null, value);
    }
    public void close()
    {
        sq.close();
    }
    public void delete(String table)
    {
        sq.delete(table,null,null);
    }
}
class entry_data extends SQLiteOpenHelper
{

    public entry_data(Context context, String name, SQLiteDatabase.CursorFactory factory,
                      int version) {
        super(context, name, factory, version);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onCreate(SQLiteDatabase sqdb) {
        // TODO Auto-generated method stub

        sqdb.execSQL("CREATE TABLE IF NOT EXISTS 'YOUR_TABLE_NAME'(Column_1 text not null,Column_2 text not null);");

    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
          onCreate(db);
    }

}

1

생성자에 대한 두 번째 인수로 "이름"문자열을 제공하는 것을 잊어 버린 경우 앱을 닫을 때 지워지는 "메모리 내"데이터베이스가 생성됩니다.


0

에뮬레이터 또는 장치에서 응용 프로그램을 제거하십시오. 앱을 다시 실행하십시오. (데이터베이스가 이미 존재하면 OnCreate ()가 실행되지 않습니다)



0

ur DatabaseHandler / DatabaseManager 클래스에서 쿼리를 다시 확인하십시오.


0

내 경우에는을 <string-array>저장하는 XML 파일에서 항목을 가져옵니다 <item>. 이것들에서 <item>나는 SQL 문자열을 잡고로 하나씩 적용 databaseBuilder.addMigrations(migration)합니다. 나는 한 가지 실수를했다. \견적 전에 추가하는 것을 잊었고 예외를 얻었다.

android.database.sqlite.SQLiteException : 해당 열 없음 : some_value (코드 1 SQLITE_ERROR) : 컴파일 중 : INSERT INTO table_name (id, name) VALUES (1, some_value)

따라서 이것은 올바른 변형입니다.

<item>
    INSERT INTO table_name(id, name) VALUES(1, \"some_value\")
</item>

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.