我有一个实现单例模式的SQLiteOpenHelper
类,有三种方法:addLogs()
,getLogs()
和deleteLogs()
。七个线程(在某些时间表由BroadcastReceiver
触发)访问数据库 - 其中六个仅使用addLogs()
,另一个使用getLogs()
并在其之前调用deleteLogs()
饰面。
我的问题是,因为最后一个线程对SQLite数据库进行两次不同的调用,所以其他线程甚至可以在调用addLogs()
之前调用deleteLogs()
,这会破坏我的输出。如何让一个线程将对SQLiteOpenHelper
的两次调用视为单个原子事务?
我尝试了什么:在ReentrantLock
中创建一个静态SQLiteOpenHelper
成员,并在他们之前和之后的七个主题中的每个主题中调用lock()
和unlock()
交易。其他六个线程仍然通过,即使最后一个仍然具有锁定,它在getLogs()
之前调用并在deleteLogs()
之后释放。
UPDATE:这是访问这两种方法的第七个线程。
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");
}
}
答案 0 :(得分:3)
SQLite的事务与db.beginTransaction()
,db.setTransactionSuccessful()
中的事务相同,用于标记要提交的Tx,db.endTransaction()
最终标记要执行的Tx。
因此,您可以在getLogs()
beginTransaction
和deleteLogs
中将其标记为已完成(并且已成功)。
[更新]
现在使用您的代码段,您可能希望在第一次调用之前和beginTransaction
块中调用finally
,这会将try-catch
阻止调用添加到endTransaction
。在try
部分结束时,如果状态正常,您可以致电setTransactionSuccessful
(delete
来电之后。