3

DBFlow を使用してデータベースに保存し、Retrofit を使用して Web サービスを呼び出しています。私のレトロフィット クラスは、私のデータベース テーブルと同じクラスです。しかし、データをテーブルに保存するために 2 つ以上のスレッドが同時に起動されると問題が発生します。テーブルへの挿入によりデータが複製され、主キーも複製されます。その後、スレッドがクラッシュしたため、スレッドが停止しました。

その解決策はありますか?

Retrofit と DBFlow のクラス

@Table(database = LocalDB.class)
@Root(name = "picture_infos")
public class PictureInfos extends BaseModel {

@PrimaryKey
@Element(name = "id_picture")
private int idPicture;

@Column
@Element(name = "id_account")
private String idAccount;

@Column
@Element(name = "folder_path")
private String folderPath;

@Column
@Element(name = "filename")
private String filename;

@Column
@Element(name = "legend", required = false)
private String legend;

public int getIdPicture() {
    return idPicture;
}

public void setIdPicture(int idPicture) {
    this.idPicture = idPicture;
}

public String getIdAccount() {
    return idAccount;
}

public void setIdAccount(String idAccount) {
    this.idAccount = idAccount;
}

public String getFolderPath() {
    return folderPath;
}

public void setFolderPath(String folderPath) {
    this.folderPath = folderPath;
}

public String getFilename() {
    return filename;
}

public void setFilename(String filename) {
    this.filename = filename;
}

public String getLegend() {
    return legend;
}

public void setLegend(String legend) {
    this.legend = legend;
}
}

レトロフィット対応のスレッド

public void onResponse(Call<AdminPictures> call, Response<AdminPictures> response) {
            AdminPictures apResponse = response.body();
            final List<PictureInfos> pictureInfos = apResponse.getPicturesList();
            new Thread(new Runnable() {
                @Override
                    public void run() {
                        try {
                            for (PictureInfos infos : pictureInfos) {
                    // This save duplicate when I've 2 or more threads
                              synchronized (infos){
                                if(!infos.exists()){
                                   infos.save();
                                 }
                              }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();

スタックトレース

    03-18 12:01:18.950 15696-19086/com.vigizen.client.kiosqueadmin E/SQLiteLog: (1555) abort at 12 in [INSERT INTO `PictureInfos`(`idPicture`,`idAccount`,`folderPath`,`filename`,`legend`) VALUES (?,?,?,?,?)]: UNIQUE constraint failed: PictureInfos.idPicture
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err: android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: PictureInfos.idPicture (code 1555)
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err:     at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err:     at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:788)
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err:     at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err:     at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err:     at com.raizlabs.android.dbflow.structure.database.AndroidDatabaseStatement.executeInsert(AndroidDatabaseStatement.java:77)
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err:     at com.raizlabs.android.dbflow.sql.SqlUtils.insert(SqlUtils.java:370)
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err:     at com.raizlabs.android.dbflow.sql.SqlUtils.save(SqlUtils.java:327)
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err:     at com.raizlabs.android.dbflow.structure.ModelAdapter.save(ModelAdapter.java:60)
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err:     at com.raizlabs.android.dbflow.structure.BaseModel.save(BaseModel.java:52)
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err:     at com.vigizen.client.kiosqueadmin.GalleryActivity$1$1.run(GalleryActivity.java:188)
    03-18 12:01:18.951 15696-19086/com.vigizen.client.kiosqueadmin W/System.err:     at java.lang.Thread.run(Thread.java:818)
4

2 に答える 2

0

ここで行っているのは、DBFlow のドキュメントの最初の「してはいけないこと」です。ここで使用する必要があるのは、データを格納するためのトランザクションです。これにより、排他的なバッチ操作のためにデータベースがロックされ、すべてのモデルを反復処理して 1 つずつ保存するよりもはるかに高速になります。

FastStoreModelTransaction.saveBuilder()基本的に、ここで使用したいのは基本的にINSERT OR UPDATE.

使用法は次のようになります。

public void onResponse(Call<AdminPictures> call, Response<AdminPictures> response) {
    AdminPictures apResponse = response.body();
    final List<PictureInfos> pictureInfos = apResponse.getPicturesList();

    FastStoreModelTransaction transaction = FastStoreModelTransaction.saveBuilder(FlowManager.getModelAdapter(PictureInfos.class))
        .addAll(pictureInfos)
        .build();

    database.executeTransaction(transaction);
}

これはバックグラウンドで自動的に実行されるため、追加のスレッドでラップする必要はありません。保存プロセスでリスナーが必要な場合は、ProcessModelTransaction代わりに を使用してください。

于 2016-12-08T11:01:20.047 に答える
-2

データベースの読み取りは、互いに中断することなく並行して実行できますが、キーがある場合、データベースへの書き込みは同期された方法で実行する必要があります。

saveを同期メソッド内に記述する必要があります。Synchronize では、一度に 1 つのスレッドのみが変更を行うことができます。

注: デフォルトでは、androidSQLiteDatabaseオブジェクトはマルチスレッドに対して安全です。DBFlowまた〜だ。複数のスレッドでヘルパーの同じインスタンスを使用していることを確認してください。

詳細

于 2016-03-18T10:11:31.063 に答える