注意:请不要将此问题标记为重复。我已经经历了几个类似的问题,但找不到满意的答案。
我一直在开发一个使用 Sqlite 数据库的应用程序。我们遵循单例模式,确保我们在整个应用程序中只能创建一个助手类实例。
public class CustomSqliteHelper extends SQLiteOpenHelper {
public static CustomSqliteHelper getInstance(Context context) {
if (instance == null) {
synchronized (CustomSqliteHelper.class) {
if (instance == null) {
instance = new CustomSqliteHelper(context);
}
}
}
return instance;
}
}
但有时应用程序会因 SQLiteDatabaseLockedException 而崩溃。我知道当多个线程/进程试图一次写入数据库时会出现此异常。即使一个线程/进程在写操作还在进行的时候试图读数据库,也会抛出这个异常。
所以我已经阅读了很多关于此的内容以及防止这种情况发生的可能方法。许多帖子建议使用 ContentProvider 而不是直接扩展 SqliteOpenHelper 类并对数据库对象执行操作。在阅读其中一篇文章时,这 post提到在使用 Content Provider 时,您不需要手动处理多线程环境。
Although the ContentProvider lacks in thread-safety, often times you will find that no further action is required on your part with respect to preventing potential race conditions. The canonical example is when your ContentProvider is backed by a SQLiteDatabase; when two threads attempt to write to the database at the same time, the SQLiteDatabase will lock itself down, ensuring that one will wait until the other has completed. Each thread will be given mutually exclusive access to the data source, ensuring the thread safety is met.
上面的引述听起来令人困惑,因为它首先提到 ContentProvider 不支持线程安全。但他得出结论,应用程序开发人员不需要为实现并发而做任何事情。
此外,如果我选择使用 SqliteOpenHelper,防止这些崩溃的最佳方法是什么?我一直在考虑为每个数据库操作使用锁。
public class CustomSqliteHelper extends SQLiteOpenHelper {
private String lock = "lock";
public void insert(){
synchronized(lock){
// Do the insert operation here.
}
}
public void update(){
synchronized(lock){
// Do the update operation here.
}
}
}
但我的一位团队成员建议我不要这样做,因为 Java 锁很昂贵。
在经历了最受欢迎的 projects 之一之后在 Github 上,我发现开发人员建议将每个数据库操作包装在一个事务中。
public void insert(ContentValues values) {
// Create and/or open the database for writing
SQLiteDatabase db = getWritableDatabase();
// It's a good idea to wrap our insert in a transaction. This helps with performance and ensures
// consistency of the database.
db.beginTransaction();
try {
// The user might already exist in the database (i.e. the same user created multiple posts).
db.insertOrThrow(TABLE_POSTS, null, values);
db.setTransactionSuccessful();
} catch (Exception e) {
Log.d(TAG, "Error while trying to add post to database");
} finally {
db.endTransaction();
}
}
我真的不确定这是否可以防止 Lock 异常?这看起来更像是一个以性能为导向的步骤。
所以最终在阅读了所有这些博客和教程之后,我仍然感到困惑。我的主要问题是
更新:根据@Mustanar 的回答,SQLiteDatabase 似乎负责锁定机制。这意味着如果您正在进行写操作,数据库将被锁定。但与此同时,如果其他线程尝试执行写操作,那么第二个操作会一直等待直到锁被释放,还是会抛出 android.sqlite.database.SQLiteDatabaseLockedException异常?
更新 2:悬赏这个问题,因为我似乎仍然不清楚答案。我只使用了 Helper 类的一个实例。但仍然出现此错误。
P.S:感谢您提出这么长的问题。
最佳答案
使用Singleton 模式来实例化SQLiteOpenHelper,因此在整个应用程序中应该存在一个单例实例。 这将确保不会发生泄漏,并使您的生活变得更加轻松,因为它消除了您在编码时忘记关闭数据库的可能性。它还将确保在整个应用程序中安全访问数据库。
此外,您不必实现自己的锁定机制。 SQLiteDatabase 维护锁定机制。因此,在特定时间只有一个事务进行,所有其他事务将使用 Sigleton.getInstance() 方法在 Queue 中。确保对数据库的单一访问点。
此外,在这种方法中,您不必关闭数据库连接,因为 SQLiteDatabase 将在事务完成后释放所有引用。所以 CustomSQLiteHelper.getInstance() 应该在您想要执行 CRUD 操作并移除锁定机制时使用。
更多信息,请浏览博客http://www.androiddesignpatterns.com/2012/05/correctly-managing-your-sqlite-database.html并查看评论。
希望这对您有所帮助。
关于java - 在多线程应用程序 Android 中访问数据库的最佳方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35358186/
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R