实现单例SqliteDatabaseHelper类的正确方法

时间:2012-10-05 16:03:26

标签: java database concurrency android-sqlite

我目前正在实现一个databasehalper类,它将从各种线程访问,所以它基本上是单例并且像这样访问:

               public class HistoryDatabaseHelper extends SQLiteOpenHelper{
                private static HistoryDatabaseHelper mInstance=null;
                public static HistoryDatabaseHelper getInstance(Context context){
            if(mInstance==null)
              mInstance=new HistoryDatabaseHelper(context.getApplicationContext());
            return mInstance;
                }

所以没有公共构造函数,这是访问帮助程序的唯一方法。

现在我的问题是我每次尝试执行任何操作时都应该打开数据库。例如,考虑辅助类的以下menmber函数:

           public void deleteContact(String staticUrl) {
           SQLiteDatabase db = this.getWritableDatabase();  // does this open a new connection each time?
                                                            //  and invade the whole purpose of 
                                                             //creating singleton helper
           db.delete(TABLE_DOWNLOAD_HISTORY, KEY_STATIC_URL + " = ?",
           new String[] { staticUrl });
           db.close();
                 }

这是正确的方法,还是应该像这样打开数据库:

            public static HistoryDatabaseHelper getInstance(Context context){
          if(mInstance==null){
               mInstance=new HistoryDatabaseHelper(context.getApplicationContext());
               mInstance.open();  // here
                           }
               return mInstance;
                   }

如果是,那么我们应该在哪里关闭数据库?

2 个答案:

答案 0 :(得分:1)

停止!等待!冻结!

"我目前正在实现一个databasehalper类,它将从各种线程访问,因此它基本上是单例并且可以这样访问:"

您说您的HistoryDatabaseHelper将从各种线程访问,您忘记同步getInstance方法?你的线程会在他们离开家之前穿上他们的跑鞋,因为他们肯定是在竞争条件下。如果您希望线程的行为像成年人一样,则需要同步getInstance方法。或者,您可以在声明本身期间实例化mInstance实例变量,并且无需同步getInstance或检查mInstance是否已在getInstance内初始化。

接下来是HistoryDatabasrHelper构造函数。您需要显式声明一个私有的HistoryDatabaseHelper构造函数,因为编译器会在您的类中放置一个公共构造函数。不这样做就像让你的邻居偷走你而不是把它们交给警察。

最后但并非最不重要的是getInstance方法的Context参数。删除此参数。让您的HistoryDatabasrHelper有一个Context实例变量,并在您的私有构造函数中初始化它,假设Context不会从一个实例更改为另一个实例。

那么你应该有一个单例数据库连接吗?我个人认为,如果你有一个单独的数据库连接池而不是一个单独的数据库连接,那将是一个更好的主意。谷歌搜索将为您提供许多用于连接池的好库。

答案 1 :(得分:0)

如果HistoryDatabaseHelper是线程安全的,那么这应该只是一个单例。调用者必须传入参数来获取单例的事实应该是一个大的红旗,因为它意味着单例的状态与此参数有关。

从线程角度来看最安全的事情是使类不是单例,只需根据需要创建一个新类。如果这会降低您的应用程序速度,那么对其进行基准测试并使用解决方案,可能使用连接池,如c3p0等。

如果您确定HistoryDatabaseHelper是线程安全的,那么在类中初始化单例,并且不需要任何参数来获取单例。