Phòng không thể xác minh tính toàn vẹn của dữ liệu


94

Tôi gặp lỗi này khi chạy chương trình với Cơ sở dữ liệu phòng

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.

Có vẻ như chúng tôi cần cập nhật phiên bản Cơ sở dữ liệu, nhưng từ đâu chúng tôi có thể làm điều đó trong Room?


2
Nếu bạn không quan tâm về dữ liệu của ứng dụng, xóa tất cả nội dung từ các thiết lập ứng dụng có thể cũng giúp đỡ, vì nó chỉ phá hủy toàn bộ DB
O-9

Câu trả lời:


131

Khi bạn lần đầu tiên gặp thông báo này, rất có thể bạn đang làm việc với một phiên bản cơ sở dữ liệu chưa được phát hành. Nếu đúng như vậy, rất có thể bạn không nên tăng phiên bản cơ sở dữ liệu . Chỉ cần xóa dữ liệu ứng dụng sẽ giúp bạn vượt qua ngoại lệ.

Nếu bạn không tăng cơ sở dữ liệu (khuyến nghị):

Bạn nên xóa dữ liệu ứng dụng của ứng dụng khỏi cài đặt Android. Ngoài ra, bạn có thể gỡ cài đặt phiên bản ứng dụng trước đó và sau đó cài đặt phiên bản mới để vượt qua ngoại lệ. Cách tiếp cận thứ hai này không hoạt động trong một số điều kiện nhất định (chẳng hạn như khi cho phép sao lưu được bật)

Vì việc xóa dữ liệu ứng dụng luôn hoạt động, tôi thực hiện theo lộ trình đó mọi lúc.

Nếu bạn tăng phiên bản cơ sở dữ liệu:

Bạn sẽ cần viết mã di chuyển cơ sở dữ liệu để giải thích cho bất kỳ thay đổi nào đối với lược đồ cơ sở dữ liệu. Xem tại đây để biết thông tin về việc di chuyển.

Thay thế cho việc viết mã di chuyển cơ sở dữ liệu là gọi fallbackToDestructiveMigrationtrình xây dựng cơ sở dữ liệu Phòng. Đây có lẽ không phải là một ý kiến ​​hay. Việc quên xóa cuộc gọi này và sau đó quên nâng cấp cơ sở dữ liệu sẽ dẫn đến mất dữ liệu.

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

Một lần nữa, không cần tăng phiên bản cơ sở dữ liệu hoặc quay trở lại quá trình di chuyển phá hủy nếu lược đồ cơ sở dữ liệu trước đó không tồn tại trong môi trường hoang dã .


4
Tôi ước gì họ sẽ bao gồm một phương pháp dự phòng khác cho trường hợp này :(
BoD

3
Trong phiên bản 1.0.0-rc1Room, điều duy nhất phù hợp với tôi là tăng phiên bản cơ sở dữ liệu.
Dick Lucas

42
Tôi có android: allowBackup = "true" trong AndroidManifest.xml của mình, điều này đã ngăn dữ liệu bị xóa ngay cả sau khi ứng dụng được gỡ cài đặt. Tôi đặt thuộc tính này thành false và sau đó cài đặt lại ứng dụng, điều này đã giúp khắc phục sự cố. Lưu ý rằng true là giá trị mặc định cho allowBackup, vì vậy nếu bạn không sử dụng nó, nó vẫn có thể khiến dữ liệu được giữ lại.
Bartek

1
@Bartek bình luận này bây giờ xứng đáng là một câu trả lời.
guness

Giải thích như vậy! Tôi đã gỡ cài đặt ứng dụng nhiều lần vì tại sao phải nâng cấp phiên bản đang phát triển? Ôi cậu bé, chưa bao giờ nghĩ rằng xóa dữ liệu khỏi cài đặt là chìa khóa quan trọng. Câu trả lời hay đấy. Nên là giải pháp được chấp nhận.
sud007

29

Theo mặc định, tệp kê khai Android có android:allowBackup="true", Điều này cho phép các ứng dụng duy trì SQLite DB của chúng khi cài đặt lại.

Giả sử DATABASE_VERSIONban đầu của bạn là 3 và sau đó bạn quyết định giảm phiên bản DB từ 3 xuống 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.
//        }
//    };
}

Bạn có thể đạt được nó như thế này

  • Xóa dữ liệu ứng dụng khỏi Cài đặt. Thao tác này sẽ xóa DB cũ hơn (DATABASE_VERSION = 3) khỏi điện thoại
  • Gỡ cài đặt ứng dụng của bạn
  • Giảm phiên bản DATABASE_VERSION xuống 1
  • Xây dựng và cài đặt lại ứng dụng của bạn

Đó là một thực hành tốt để giữ DATABASE_VERSIONliên tục.


1
Nó sẽ không ảnh hưởng đến những người dùng sẽ cập nhật ứng dụng từ Play Store chứ?
nimi0112

1
Tôi đã làm theo cách tương tự, nhưng không hiệu quả. Thậm chí, tôi đang cố gắng để cài đặt trên một thiết bị mới từ Android Studio, nó cho thấy cùng một lỗi: x
Sadat

@ nimi0112 Đối với biến thể phát hành của bạn, bạn nên cho phép sao lưu, tuy nhiên đối với biến thể gỡ lỗi của bạn, bạn có thể tắt nó đi
Chad Mx

25

android: allowBackup = "true" bên trong AndroidManifest.xml ngăn dữ liệu bị xóa ngay cả sau khi ứng dụng được gỡ cài đặt.

Thêm cái này vào tệp kê khai của bạn:

android:allowBackup="false"

và cài đặt lại ứng dụng.

Lưu ý: Hãy chắc chắn rằng bạn thay đổi nó trở lại true sau này nếu bạn muốn tự động sao lưu.

Giải pháp khác:

Kiểm tra danh tính của tệp json cũ của bạn và tệp json mới trong thư mục apps \ schema.

Nếu IDHash khác, nó sẽ đưa ra lỗi đó. Tìm hiểu những gì bạn đã thay đổi bằng cách so sánh cả hai tệp json nếu bạn không muốn thay đổi bất cứ điều gì.

Đảm bảo rằng bạn có exportSchema = true.

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

tệp giản đồ json:

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

mã:

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.");
    }
}

20

Câu trả lời của Aniruddh Parihar đã cho tôi một gợi ý và nó đã giải quyết được.

Tìm kiếm một lớp học mà bạn đã mở rộng RoomDatabase. Ở đó bạn sẽ tìm thấy phiên bản như dưới đây:

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

chỉ cần tăng phiên bản và vấn đề được giải quyết.


11

Nó rất đơn giản như được hiển thị trong nhật ký

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

Đơn giản, hãy chuyển đến lớp Phiên bản cơ sở dữ liệu của bạn và nâng cấp phiên bản DB của bạn bằng cách tăng 1 so với hiện tại.

Ví dụ: Tìm chú thích @Database trong dự án của bạn như bên dưới

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

Đây là phiên bản = 1, là phiên bản cơ sở dữ liệu, bạn chỉ cần tăng nó lên một cái.


1
Vâng, tôi đã gặp lỗi đó, đó là lý do tại sao tôi cũng đã đề cập trong câu hỏi rằng It seems we need to update database version. Nhưng tôi đã không nhận được nơi phiên bản đó được đề cập. Dù sao, cảm ơn vì gợi ý đó.
Ravi

Bạn đã nhập lại thông báo lỗi nhưng chưa cung cấp thêm bất kỳ thông tin nào để giải quyết sự nhầm lẫn của người đăng ban đầu.
Carl Rossman

@CarlRossman: Bạn phải tìm lớp Cơ sở dữ liệu của mình trong dự án nơi bạn đã sử dụng Chú thích cơ sở dữ liệu, trên lớp đó, bạn sẽ tìm thấy phiên bản Cơ sở dữ liệu (Giá trị số nguyên), chỉ cần tăng nó lên một so với hiện tại.
Aniruddh Parihar

7

1: - Có vẻ như chúng tôi cần cập nhật phiên bản cơ sở dữ liệu (tăng thêm 1)

nhập mô tả hình ảnh ở đây

Thứ 2 Gỡ cài đặt ứng dụng hoặc Xóa dữ liệu ứng dụng


6

Trên điện thoại Android:

Gỡ cài đặt ứng dụng hoặc Xóa dữ liệu ứng dụng

Để xóa dữ liệu ứng dụng: Đi tới cài đặt -> Ứng dụng -> Chọn ứng dụng của bạn -> Bộ nhớ -> Xóa dữ liệu

Việc gỡ cài đặt (và cài đặt lại) không hoạt động trong mọi trường hợp, vì vậy hãy thử xóa dữ liệu trước!


Vâng, điều đó đã hoạt động. Nhưng kỳ lạ là tôi đã gặp sự cố này trên một thiết bị đã bị xóa hoàn toàn và thiết lập mới ngay bây giờ. Nhưng chỉ cần xóa dữ liệu đã giải quyết.
Ajith Memana

Điều này không nên được thực hiện trên sản xuất. Bạn không nên buộc tất cả người dùng của mình xóa dữ liệu khỏi ứng dụng. Tốt hơn nên viết mã di chuyển bằng cách tăng phiên bản lên 1 trong cơ sở dữ liệu Phòng của bạn.
Rajeev Jayaswal

5

Trong trường hợp của tôi, android:allowBackup="false"việc biến nó thành đúng thành sai đã hoạt động, vì điều này cũng đã mang lại cho tôi những cơn ác mộng trước đây, đây là điều kỳ lạ nhất tại sao cài đặt này được bật theo mặc định!


5

Để khắc phục sự cố trong kotlin:

Đầu tiên

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

Thứ hai

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 ''")
        }
    }

Ngày thứ ba

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

Để biết thêm chi tiết, hãy kiểm tra tài liệu chính thức


4

Vấn đề này chủ yếu xảy ra trong quá trình phát triển.

Nếu bạn thay đổi lược đồ của mình, tức là, đổi tên / thêm / sửa đổi lớp của bạn chứa thực thể bảng, tính toàn vẹn giữa việc thoát db trong bản dựng trước đó của bạn xung đột với bản dựng mới.

xóa dữ liệu ứng dụng hoặc cài đặt bản dựng mới sau khi gỡ cài đặt bản dựng trước đó .

Bây giờ, db cũ sẽ không xung đột với db mới hơn.


Sau đó vẫn là tai nạn
user7856586

ngoại lệ là gì? vui lòng đưa lên nhật ký để thu hẹp vấn đề.
Extremis II

2
Cảm ơn, mọi thứ đều ổn. Tôi đọc về android:allowBackup="true"và sử dụng nó một cách khôn ngoan
user7856586

1
@ user7856586 Vậy còn allowBackup thì sao? Bạn có thể vui lòng khai sáng cho chúng tôi với trí tuệ của bạn?
Thật nực cười

@Ridcully bạn có thể đọc về điều đó ở đây Tại sao bạn lại tức giận như vậy?
user7856586,

3

Trong trường hợp của tôi, tôi có một lớp AppDatabase.

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

Tôi đã cập nhật số phiên bản này và nó đã giải quyết được sự cố. Sự cố phát sinh vì tôi đã thêm một thuộc tính trong lớp SongInfo và quên cập nhật số phiên bản.

Hy vọng nó sẽ giúp một ai đó.


2

Nếu bạn đang nâng cấp phiên bản Room lên 1.0.0-alpha9 từ phiên bản cũ thì hãy truy cập bài viết dưới đây. Bài viết rất tốt để di chuyển từ phiên bản cũ sang phiên bản 1.0.0-alpha9.

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

Trong Room Phiên bản mới 1.0.0-alpha9 Room bổ sung hỗ trợ cho ràng buộc NOT NULL.

Điều đó sẽ thay đổi lược đồ mà Room tạo ra. Bởi vì nó thay đổi lược đồ, nó cũng thay đổi IDHash của DB và được Room sử dụng để xác định duy nhất mọi phiên bản DB. Do đó, chúng tôi cần một cuộc di chuyển


2

Trong trường hợp của tôi ContentProvider và cơ sở dữ liệu phòng hoạt động cùng nhau, vì vậy trước tiên hãy xóa tất cả lệnh gọi lại của ContentProvider trên toàn bộ ứng dụng với lớp cơ sở dữ liệu mở rộng Lớp SqlLiteOpenHelper


2

Trong trường hợp của tôi, tôi đang sử dụng một giao dịch bên trong quá trình di chuyển và Room không thể cập nhật hàm băm bằng Trình trợ giúp di chuyển

@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() 
}

Tôi đấu tranh trong vài giờ và đây là giải pháp !! cảm ơn bạn!!
Javier

1
Trong ví dụ trên, không phải giao dịch là một vấn đề. Bạn quên đặt giao dịch thành công trước khi kết thúc: <pre> <code> database.beginTransaction () database.setTransactionSuccessful () database.endTransaction () </code> </pre>
birukoff

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

Thay đổi số phiên bản trong lớp RoomDatabase của bạn. Tăng số phiên bản.


2

Nếu phiên bản lược đồ tăng dần không hoạt động với bạn, hãy cung cấp di chuyển cơ sở dữ liệu của bạn. Để làm điều đó, bạn cần khai báo việc di chuyển trong trình tạo cơ sở dữ liệu:

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");
    }
};

Vâng, đây là cách thích hợp
Bipin Bharti

1

Tôi vừa gặp sự cố tương tự trong một thử nghiệm cà phê espresso và điều duy nhất khắc phục được sự cố đó là xóa dữ liệu và cũng gỡ cài đặt các ứng dụng thử nghiệm androidx như:

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

0

Trong trường hợp của tôi, tôi đang cập nhật cơ sở dữ liệu mà tôi sẽ đóng gói trước ứng dụng của mình. Không có đề xuất nào ở đây hiệu quả. Nhưng cuối cùng tôi đã phát hiện ra rằng tôi có thể mở tệp .db trong một chương trình cơ sở dữ liệu (tôi đã sử dụng "Trình duyệt DB cho SQLite") và thay đổi thủ công "Phiên bản người dùng" từ 2 trở lại 1. Sau đó, nó hoạt động hoàn hảo.

Tôi đoán rằng bất kỳ bản cập nhật nào bạn thực hiện đều thay đổi phiên bản người dùng này và đây là lý do tại sao tôi vẫn gặp lỗi này.


Bạn có thể giúp tôi với cùng? Tôi không thể tìm thấy phiên bản trong Trình duyệt DB cho SQLite
GreenROBO Ngày

Nó nằm trong tab "Chỉnh sửa pragmas". Nó được gọi là "Phiên bản Người dùng".
Gavin Wright

Đúng. Tôi hiểu rồi. Cảm ơn sự giúp đỡ của Gavin :)
GreenROBO

-1

Trong trường hợp của tôi, tôi đã thử tất cả những điều trên. Dường như không có gì hoạt động nên giải pháp cho tôi chỉ đơn giản là thiết lập android:allowBackup="false", cài đặt ứng dụng sau đó đặt nó trở lại true

Hy vọng nó sẽ giúp những người khác :)


1
Đây chính xác là những gì tôi đã trả lời, tại sao phải lặp lại câu trả lời?
Divyanshu Negi

-2

Tôi gặp lỗi tương tự trong chương trình đào tạo của Codelabs. Trong một buổi đào tạo, tôi đã tạo một dự án và nó chạy thành công với tất cả các hoạt động cơ sở dữ liệu. Trong phiên tiếp theo, tôi đã làm việc với một repo khác, nhưng nó là một phần mở rộng của dự án trước đó, Từ lần xây dựng đầu tiên của ứng dụng mở rộng, tôi chỉ gặp lỗi.

Có thể Studio giữ các kỹ thuật xác thực với cơ sở dữ liệu phòng bị thiếu trong bản dựng mới.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.