2

我有一个SQLiteOpenHelper实现单例模式的类,并具有三种方法:addLogs()getLogs()deleteLogs()BroadcastReceiver七个线程(由 a在某些时间表触发)访问数据库——其中六个仅使用addLogs(),另一个在完成之前使用getLogs()和调用。deleteLogs()

我的问题是,因为最后一个线程对 SQLite 数据库进行了两次不同的调用,所以其他线程addLogs()甚至可以在调用之前deleteLogs()调用,这会破坏我的输出。如何使一个线程将两个调用SQLiteOpenHelper视为单个原子事务?

我尝试过的:在 , 中创建一个静态ReentrantLock成员,并在事务之前和之后从七个线程中的每一个SQLiteOpenHelper调用lock()and 。unlock()即使最后一个线程仍然有锁,其他六个线程仍然可以通过,它在之前调用getLogs()并在之后释放deleteLogs()

更新:这是访问这两种方法的第七个线程。

public class Uploader extends Thread {

    private Context context;

    public Uploader(Context context) {
        this.context = context;
    }

    @Override
    public void run() {
        Logger.d("STARTED: Uploader");
        DB db = DB.getInstance(context);
        List<JsonLog> logs = db.getLogs(); // FIRST CALL
        String json = new Gson().toJson(logs); // convert to JSON

        // connect to the server and upload
        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(This.URL);
        post.setHeader("content-type", "application/json");
        try {
            Logger.d("to upload: " + json);
            StringEntity se = new StringEntity(json);
            post.setEntity(se);
            StatusLine status = client.execute(post).getStatusLine();
            // if upload is successful
            if (status.getStatusCode() == HttpStatus.SC_OK) {
                db.deleteLogs(); // SECOND CALL
            } else {
                Logger.d("Uploader failed. " + status.getStatusCode() + ": " + status.getReasonPhrase());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Logger.d("FINISHED: Uploader");
    }

}
4

1 回答 1

3

SQLite 有事务db.beginTransaction()db.setTransactionSuccessful()用于标记要提交的 Tx 并db.endTransaction()最终将 Tx 标记为完成。

因此,您可以在您的getLogs()操作中将beginTransactiondeleteLogs标记为已完成(并且成功)。

[Update] Now with your code snippet you probably would want to call beginTransaction before your 1st call and in a finally block, that adds to the try-catch block call into endTransaction. At the end of the try part if the status is ok, you would call setTransactionSuccessful (after the delete call.

于 2012-12-24T13:35:35.507 回答