Room에서 데이터 무결성을 확인할 수 없습니다.


91

Room Database로 프로그램을 실행하는 동안이 오류가 발생합니다.

Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. 
You can simply fix this by increasing the version number.

데이터베이스 버전을 업데이트해야하는 것 같지만 Room에서 할 수있는 곳은 어디입니까?


2
앱의 데이터에 신경 쓰지 않는다면 전체 DB 만 파괴하기 때문에 애플리케이션 설정에서 모든 콘텐츠를 삭제하는 것도 도움이 될 수 있습니다
O-9

답변:


131

이 메시지를 처음 접했을 때 릴리스되지 않은 버전의 데이터베이스에 대해 작업 할 가능성이 높습니다. 이 경우 데이터베이스 버전을 늘리지 않아야합니다 . 앱 데이터를 지우는 것만으로도 예외를 통과하게됩니다.

데이터베이스를 증가시키지 않는 경우 (권장) :

Android 설정에서 애플리케이션의 앱 데이터를 지워야합니다. 또는 이전 앱 버전을 제거한 다음 새 버전을 설치하여 예외를 전달할 수 있습니다. 이 후자의 접근 방식은 특정 조건 (예 : 백업 허용이 활성화 된 경우)에서 작동하지 않습니다.

응용 프로그램 데이터 지우기는 항상 작동하므로 매번 해당 경로를 사용합니다.

데이터베이스 버전을 증가시키는 경우 :

데이터베이스 스키마의 변경 사항을 설명하기 위해 데이터베이스 마이그레이션 코드를 작성해야합니다. 마이그레이션에 대한 정보는 여기 를 참조 하십시오 .

데이터베이스 마이그레이션 코드를 작성하는 다른 방법 fallbackToDestructiveMigration은 Room 데이터베이스 빌더 를 호출 하는 것입니다. 이것은 아마도 좋은 생각이 아닙니다. 이 호출을 제거하는 것을 잊은 다음 데이터베이스를 업그레이드하는 것을 잊으면 데이터가 손실됩니다.

// Using this fallback is almost certainly a bad idea
Database database = Room.databaseBuilder(context, Database.class, DATABASE_NAME)
        .fallbackToDestructiveMigration()
        .build();

이전 데이터베이스 스키마가 라이브가 아닌 경우 다시, 둘 다 데이터베이스 버전을 증가하거나 파괴 이전에 다시 떨어지는 것은 필요하지 않습니다 야생에서 .


4
이 경우에 다른 대체 방법을 포함하고 싶습니다. (
BoD

3
1.0.0-rc1Room 버전 에서 나를 위해 일한 유일한 것은 데이터베이스 버전을 증가시키는 것입니다.
Dick Lucas

42
내 AndroidManifest.xml에 android : allowBackup = "true"가있어 앱을 제거한 후에도 데이터가 지워지지 않았습니다. 이 속성을 false로 설정 한 다음 앱을 다시 설치하여 문제를 해결했습니다. true는 allowBackup의 기본값이므로 아예 사용하지 않으면 데이터가 유지 될 수 있습니다.
Bartek

1
@Bartek이 의견은 이제 답이 될 가치가 있습니다.
guness

그런 설명! 개발중인 버전을 업그레이드하는 이유 때문에 계속해서 앱을 제거했습니다. 오 이런, 설정에서 데이터를 지우는 것이 핵심이라고 생각하지 못했습니다. 좋은 대답입니다. 허용되는 솔루션이어야합니다.
sud007

29

기본적으로 Android 매니페스트에는 android:allowBackup="true", 앱이 재설치시 SQLite DB를 유지할 수 있습니다.

DATABASE_VERSION처음에 3 살이었고 DB 버전을 3에서 1로 줄 였다고 가정 해 보겠습니다.

@Database(entities = {CallRecording.class}, version = DATABASE_VERSION)
public abstract class AppDatabase extends RoomDatabase {
    public abstract RecordingDAO recordingDAO();

//    static final Migration MIGRATION_1_2 = new Migration(1, 2) {
//        @Override
//        public void migrate(SupportSQLiteDatabase database) {
//            // Since we didn't alter the table, there's nothing else to do here.
//        }
//    };
}

이렇게 할 수 있습니다

  • 설정에서 앱 데이터를 지 웁니다. 전화에서 이전 DB (DATABASE_VERSION = 3)를 제거합니다.
  • 앱 제거
  • DATABASE_VERSION 버전을 1로 줄입니다.
  • 앱 빌드 및 재설치

DATABASE_VERSION일정하게 유지하는 것이 좋습니다 .


1
Play 스토어에서 앱을 업데이트하는 사용자에게 영향을주지 않나요?
nimi0112

1
나는 같은 방법을 따랐지만 작동하지 않았습니다. Android Studio에서 새 기기에 설치하려고해도 동일한 오류가 표시됩니다. x
Sadat

@ nimi0112 릴리스 변형의 경우 백업을 허용해야하지만 디버그 변형의 경우 해제 할 수 있습니다
Chad Mx 19

25

AndroidManifest.xml 내부의 android : allowBackup = "true"는 앱이 제거 된 후에도 데이터가 지워지지 않도록합니다.

다음을 매니페스트에 추가하십시오.

android:allowBackup="false"

앱을 다시 설치하십시오.

참고 : 자동 백업을 원하면 나중에 다시 true로 변경하십시오.

또 다른 해결책 :

이전 json 파일의 identityHash와 apps \ schema 폴더에서 새 json 파일을 확인하십시오.

identityHash가 다른 경우 해당 오류가 발생합니다. 아무것도 변경하지 않으려면 두 json 파일을 비교하여 변경 한 내용을 찾으십시오.

exportSchema = true인지 확인하십시오.

@Database(entities = {MyEntity.class, ...}, version = 2, exportSchema = true)

json 스키마 파일 :

  "formatVersion": 1,
  "database": {
    "version": 2,
    "identityHash": "53cc5ef34d2ebd33c8518d79d27ed012",
    "entities": [
      {

암호:

private void checkIdentity(SupportSQLiteDatabase db) {
    String identityHash = null;
    if (hasRoomMasterTable(db)) {
        Cursor cursor = db.query(new SimpleSQLiteQuery(RoomMasterTable.READ_QUERY));
        //noinspection TryFinallyCanBeTryWithResources
        try {
            if (cursor.moveToFirst()) {
                identityHash = cursor.getString(0);
            }
        } finally {
            cursor.close();
        }
    }
    if (!mIdentityHash.equals(identityHash) && !mLegacyHash.equals(identityHash)) {
        throw new IllegalStateException("Room cannot verify the data integrity. Looks like"
                + " you've changed schema but forgot to update the version number. You can"
                + " simply fix this by increasing the version number.");
    }
}

19

Aniruddh Parihar 의 대답은 나에게 힌트를 주었고 해결되었습니다.

확장 한 클래스를 검색합니다 RoomDatabase. 다음과 같은 버전이 있습니다.

@Database(entities = {YourEntity.class}, version = 1)

버전을 올리면 문제가 해결됩니다.


12

로그에 표시된 것처럼 매우 간단합니다.

Looks like you've changed schema but forgot to update the Database version number. 
You can simply fix this by increasing the version number.

데이터베이스 버전 클래스로 이동하여 현재 버전에서 1을 늘려서 DB 버전을 업그레이드하십시오.


1
예, 그 오류가 발생했습니다 It seems we need to update database version. 그래서 질문에서 . 그러나 나는 그 버전이 언급 된 곳을 찾지 못했습니다. 어쨌든 그 힌트에 감사드립니다.
Ravi

7

1 :-데이터베이스 버전을 업데이트해야하는 것 같습니다 (1 씩 증가).

여기에 이미지 설명 입력

2nd 앱 제거 또는 앱 데이터 지우기


6

Android 휴대 전화 :

앱 제거 또는 앱 데이터 지우기

앱 데이터 삭제 : 이동 설정-> 앱-> 앱 선택-> 저장소-> 데이터 지우기

모든 경우에 제거 (및 다시 설치)가 작동하는 것은 아니므로 먼저 데이터를 지우십시오!


네, 작동했습니다. 하지만 이상하게도 완전히 지워지고 방금 새로 설정 한 장치 에서이 문제가 발생했습니다. 그러나 단순히 데이터를 지우면 해결되었습니다.
Ajith Memana

프로덕션에서는이 작업을 수행해서는 안됩니다. 모든 사용자가 앱에서 데이터를 지우도록 강요해서는 안됩니다. Room 데이터베이스에서 버전을 1 씩 늘려 마이그레이션 코드를 작성하는 것이 좋습니다.
Rajeev Jayaswal

5

제 경우에는 android:allowBackup="false"이 설정이 기본적으로 활성화되어있는 이유 중 가장 이상한 점입니다.


4

이 문제는 대부분 개발 단계에서 발생합니다.

스키마를 변경하는 경우 즉, 테이블 엔티티를 포함하는 클래스의 이름을 변경 / 추가 / 수정하면 이전 빌드에서 종료 된 db 간의 무결성이 새 빌드와 충돌합니다.

앱 데이터를 지우 거나 이전 빌드를 제거한 후 새 빌드를 설치합니다 .

이제 이전 db는 최신 db와 충돌하지 않습니다.


그 후에도 여전히 충돌
user7856586

예외는 무엇입니까? 문제를 좁히기 위해 로그를 올려주세요.
Extremis II

2
감사합니다. 이제 모든 것이 정상입니다. 내가 읽어 android:allowBackup="true"현명하게 사용
user7856586

1
@ user7856586 그렇다면 allowBackup은 어떻습니까? 당신의 지혜로 우리를 계몽 해 주시겠습니까?
Ridcully

@Ridcully 당신은 여기 에 대해 읽을 수 있습니다. 왜 그렇게 화가 났습니까?
user7856586

4

kotlin에서 문제를 해결하려면 :

먼저

@Database(entities = [Contact::class], version = 2)

둘째

val MIGRATION_1_2 = object : Migration(1, 2) {
        override fun migrate(database: SupportSQLiteDatabase) {
            database.execSQL("ALTER TABLE Contact ADD COLUMN seller_id TEXT NOT NULL DEFAULT ''")
        }
    }

제삼

private fun buildDatabase(context: Context) = Room.databaseBuilder(
            context.applicationContext,
            EpayDatabase::class.java,
            "epay"
        )
            .addMigrations(MIGRATION_1_2)
            .build()

자세한 내용은 공식 문서를 확인하세요.


3

제 경우에는 AppDatabase 클래스가 있습니다.

@Database(entities = {GenreData.class, MoodData.class, SongInfo.class,
    AlbumsInfo.class, UserFolderListsData.class, UserPlaylistResponse.PlayLists.class, InternetConnectionModel.class}, version = 3, exportSchema = false)

이 버전 번호를 업데이트하여 문제가 해결되었습니다. SongInfo 클래스에 속성을 추가하고 버전 번호를 업데이트하는 것을 잊었 기 때문에 문제가 발생했습니다.

누군가에게 도움이되기를 바랍니다.


2

Room 버전을 이전 버전에서 1.0.0-alpha9로 업그레이드하는 경우 아래 문서를 참조하십시오. 이전 버전에서 1.0.0-alpha9 버전으로 마이그레이션하기위한 아주 좋은 문서입니다.

https://medium.com/@manuelvicnt/android-room-upgrading-alpha-versions-needs-a-migration-with-kotlin-or-nonnull-7a2d140f05b9

In Room 새 버전 1.0.0-alpha9 Room은 NOT NULL 제약 조건에 대한 지원을 추가합니다.

Room이 생성하는 스키마가 변경됩니다. 스키마를 변경하기 때문에 DB의 identityHash도 변경되며 Room에서 모든 DB 버전을 고유하게 식별하는 데 사용됩니다. 따라서 마이그레이션이 필요합니다.


2

제 경우에는 ContentProvider와 룸 데이터베이스가 함께 작동하므로 먼저 SqlLiteOpenHelper 클래스를 확장하는 데이터베이스 클래스를 사용하여 애플리케이션 전체에서 ContentProvider의 모든 콜백을 제거하십시오.


2

제 경우에는 마이그레이션 내부에서 트랜잭션을 사용하고 있었고 Room은 마이그레이션 도우미를 사용하여 해시를 업데이트 할 수 없습니다.

@get:Rule
val migrationTestHelper: MigrationTestHelper =

MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
                C2GDatabase::class.java.canonicalName,
                FrameworkSQLiteOpenHelperFactory()) 
/* Testing method throws error*/
db = migrationTestHelper.runMigrationsAndValidate(C2GDatabase.DB_NAME,
            3,
            false,
            C2GDatabase.Migration_1_2(),
            C2GDatabase.Migration_2_3())


override fun migrate(database: SupportSQLiteDatabase) {

/** 
    Error
    database.beginTransaction()
**/
database.execSQL("PRAGMA foreign_keys=off;")
database.execSQL("ALTER TABLE user RENAME TO user_old;")
database.execSQL("CREATE TABLE user ( id_user INTEGER PRIMARY KEY AUTOINCREMENT, external_id INTEGER NOT NULL;")
database.execSQL("INSERT INTO user ( id_user, external_id ) " +
                        " SELECT               id_user, external_id" +  
                        " FROM                 user_old;")

database.execSQL("CREATE UNIQUE INDEX idx_unique_user ON user (external_id);")
database.execSQL("PRAGMA foreign_keys=on;")
database.execSQL("DROP TABLE user_old;")
//database.endTransaction() 
}

나는 몇 시간 동안 고생했고 이것이 해결책이었다 !! 감사합니다!!
Javier

1
위의 예에서 문제가되는 것은 거래가 아닙니다. 트랜잭션을 종료하기 전에 성공적으로 설정하는 것을 잊었습니다 : <pre> <code> database.beginTransaction () database.setTransactionSuccessful () database.endTransaction () </ code> </ pre>
birukoff

2
@Database(entities = {Tablename1.class, Tablename2.class}, version = 3, exportSchema = false)

RoomDatabase 클래스에서 버전 번호를 변경합니다. 버전 번호를 늘리십시오.


2

스키마 버전을 늘려도 효과가없는 경우 데이터베이스 마이그레이션을 제공하십시오. 이를 수행하려면 데이터베이스 빌더에서 마이그레이션을 선언해야합니다.

Room.databaseBuilder(context, RepoDatabase.class, DB_NAME)
  .addMigrations(FROM_1_TO_2)
.build();

static final Migration FROM_1_TO_2 = new Migration(1, 2) {
@Override
public void migrate(final SupportSQLiteDatabase database) {
    database.execSQL("ALTER TABLE Repo 
                     ADD COLUMN createdAt TEXT");
    }
};

예, 올바른 방법입니다
Bipin Bharti

1

나는 에스프레소 테스트에서 비슷한 문제가 있었고 그것을 고친 유일한 것은 데이터를 지우고 androidx 테스트 APK를 다음과 같이 제거하는 것뿐입니다.

adb uninstall androidx.test.orchestrator
adb uninstall androidx.test.services

0

제 경우에는 앱으로 미리 패키징 할 데이터베이스를 업데이트하고있었습니다. 여기에서 제안 된 사항 중 어느 것도 효과가 없었습니다. 하지만 마침내 데이터베이스 프로그램 ( "DB Browser for SQLite"사용)에서 .db 파일을 열고 "사용자 버전"을 2에서 1로 수동으로 변경할 수 있다는 것을 알게되었습니다. 그 후 완벽하게 작동했습니다.

나는 당신 이이 사용자 버전을 변경하는 모든 업데이트를 추측하며 이것이이 오류가 계속 발생하는 이유입니다.


저를 도와 줄 수 있습니까? SQLite 용 DB 브라우저에서 버전을 찾을 수 없습니다
GreenROBO

"pragma 편집"탭 아래에 있습니다. "사용자 버전"이라고합니다.
Gavin Wright

예. 알았어. 도움을 주셔서 감사합니다. Gavin :)
GreenROBO

-1

제 경우에는 위의 모든 것을 시도했습니다. 아무것도 작동하지 않는 것 같았으므로 솔루션은 단순히 설정 android:allowBackup="false"하고 앱을 설치 한 다음 다시 true 로 설정하는 것이 었습니다.

다른 사람들에게 도움이되기를 바랍니다. :)


1
이것이 바로 내가 대답 한 것입니다. 왜 대답을 반복합니까?
Divyanshu Negi

-2

Codelabs의 교육 프로그램 중에 동일한 오류가 발생했습니다. 한 교육 세션에서 프로젝트를 만들고 모든 데이터베이스 작업을 성공적으로 실행했습니다. 다음 세션에서는 다른 저장소로 작업했지만 이전 프로젝트의 확장이었고 확장 앱의 첫 번째 빌드부터 오류가 발생했습니다.

아마도 Studio는 새 빌드에서 누락 된 방 데이터베이스로 인증 기술을 유지합니다.

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