简体   繁体   English

实现单例SqliteDatabaseHelper类的正确方法

[英]Proper way of implementing a singleton SqliteDatabaseHelper class

I am currently implementing a databasehalper class which will be accessed from various threads so it'll basically be singleton and accessed like this : 我当前正在实现一个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;
                }

So there is no public constructor and this is the only way of accessing the helper . 因此,没有公共构造函数,这是访问助手的唯一方法。

Now my question is that should i open the database everytime i try to perform any operation . 现在我的问题是,我每次尝试执行任何操作时都应该打开数据库。 For example consider the following menmber function of the helper class : 例如,考虑以下helper类的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();
                 }

So is this is the proper way or should i open the database once like this : 那么这是正确的方法还是我应该像这样打开数据库:

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

if so then where should we close the database ? 如果是这样,那我们应该在哪里关闭数据库?

Stop! 停止! Wait! 等待! Freeze! 冻结!

"I am currently implementing a databasehalper class which will be accessed from various threads so it'll basically be singleton and accessed like this : " “我目前正在实现一个databasehalper类,该类可以从各个线程进行访问,因此它基本上将是单例的,并且可以这样访问:”

You say your HistoryDatabaseHelper will be accessed from various threads and you forget to synchronize the getInstance method? 您说您的HistoryDatabaseHelper将通过各种线程进行访问,而您忘记了同步getInstance方法? Your threads are going to wear their running shoes before they leave home since they are definitely up for a race condition. 您的线程在离开家之前要穿上跑鞋,因为它们肯定适合比赛条件。 You need to synchronize your getInstance methods if you want your threads to behave like grown ups. 如果您希望线程的行为像大人一样,则需要同步getInstance方法。 Alternately, you can instantiate mInstance instance variable during declaration itself and avoid the need to synchronize getInstance or check whether mInstance has already been initialized inside getInstance. 或者,您可以在声明本身期间实例化mInstance实例变量,而无需同步getInstance或检查getInstance内部是否已初始化mInstance。

Next up is the HistoryDatabasrHelper constructor. 接下来是HistoryDatabasrHelper构造函数。 You need to explicitly declare a private HistoryDatabaseHelper constructor since the compiler will place a public constructor in your class otherwise. 您需要显式声明一个私有的HistoryDatabaseHelper构造函数,因为否则编译器会将公共构造函数放置在您的类中。 Not doing this is like letting your neighbour's steal from you and not handing them over to the cops. 不这样做,就像是让邻居的窃贼从您手中窃取,而不是将其移交给警察。

Last but not the least is the Context parameter for the getInstance method. 最后但并非最不重要的是getInstance方法的Context参数。 Remove this parameter. 删除此参数。 Let your HistoryDatabasrHelper have a Context instance variable and initialize it within your private constructor assuming that the Context is not going to change from one instance to another. 让您的HistoryDatabasrHelper具有一个Context实例变量,并在您的私有构造函数中对其进行初始化,假设Context不会从一个实例更改为另一个实例。

So should you have a singleton database connection? 那你应该有一个单例数据库连接吗? I personally think it would be a better idea if you had a singleton database connection pool instead of a singleton database connection. 我个人认为,如果您有一个单例数据库连接池而不是一个单例数据库连接,那将是一个更好的主意。 A Google search will give you a lot of good libraries for connection pooling out there. Google搜索将为您提供许多很好的库,用于在那里进行连接池。

This should only be a singleton if HistoryDatabaseHelper is thread-safe. 如果HistoryDatabaseHelper是线程安全的,则只能是单例。 The fact that callers must pass in a parameter to get the singleton should be a big red flag, because it implies that the state of the singleton is related to this parameter. 调用者必须传递参数以获取单例的事实应该是一个大的危险信号,因为这意味着单例的状态与此参数有关。

The safest thing from a threading perspective is to make the class not a singleton, just create a new one as needed. 从线程的角度来看,最安全的事情是使该类不是单例,只需根据需要创建一个新类。 If this turns out to be slowing down your application, then benchmark it and work on a solution, possibly using connection pooling like c3p0, etc. 如果事实证明这使您的应用程序变慢,请对其进行基准测试并开发解决方案,可能使用诸如c3p0等的连接池。

If you're sure that HistoryDatabaseHelper is thread-safe, then initialize the singleton within the class, and don't require any parameter to get the singleton. 如果确定HistoryDatabaseHelper是线程安全的,则在类中初始化单例,并且不需要任何参数即可获取单例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM