【问题标题】:how to make SQLite connections more efficient如何使 SQLite 连接更高效
【发布时间】:2014-10-09 10:10:26
【问题描述】:

在活动运行的整个过程中保持本地 sqlite 连接打开有什么好处?

我通常创建一个新连接,然后在每个执行数据库操作的方法中关闭它。它看起来像这样:

myMethod(Context context){
    LocalDBHelper localDBHelper = new LocalDBHelper(context); //extended SQLiteOpenHelper 
    SQLiteDatabase db = localDBHelper.getWritableDatabase();
    ...
    localDBHelper.close();
}

因此,在典型的用户会话中,这会发生大约 10 次。在onResume() 中创建一个连接,在所有数据库访问方法中使用它,最后在onPause() 中关闭它是否有意义?

【问题讨论】:

    标签: android sqlite android-sqlite


    【解决方案1】:

    在活动运行的整个过程中保持本地 sqlite 连接打开有什么好处?

    您通常需要在整个流程生命周期中建立一个“连接”。特别是,您不希望跨多个线程同时使用多个“连接”。 Android 中 SQLite 的所有线程安全逻辑都基于对所有这些线程使用单个 SQLiteDatabase(因此,单个 SQLiteOpenHelper),因此可以进行适当的锁定。

    【讨论】:

    • @faizal:“但是我将如何在进程级别初始化 SQLiteDatabase?” -- 懒惰初始化一个单例。 “因此,创建一个在整个进程生命周期中打开的进程级 SQLiteDatabase 会导致相同的错误”——我还没有看到。
    • @faizal:欢迎您忽略该消息。或者,欢迎您尝试我的建议,看看您是否继续收到该消息。或者,也欢迎你滚动自己的线程同步机制,加上不断打开和关闭数据库的开销。
    • @faizal:“如果服务尝试读取数据,而事务正在更新它,它将读取未提交的数据” - 不,它不会,因为这不是事务的工作方式在数据库中。
    • @faizal:“但是,在同一数据库连接中发生的操作之间没有隔离”——这是由SQLiteDatabase 提供的。 “如果 X 使用 BEGIN IMMEDIATE 开始写入事务”——那么不要使用 BEGIN IMMEDIATE(转换为 beginTransaction()SQLiteDatabase 的非独占版本),除非你知道你有唯一正在运行的线程。
    • @whizzle:我不惜一切代价避免使用多进程 Android 应用程序。话虽如此,AFAIK,它将像 SQLite 在其他环境(例如 Rails)中一样工作,使用 OS 文件级锁定进行隔离。
    【解决方案2】:

    基于@CommonsWare 的回答,我已经实现了一个单例模式,以使用延迟实例化来拥有LocalDBHelper 的单个应用程序范围实例。到目前为止它工作正常,并且无需为每个操作实例化和关闭帮助程序/数据库。

    public class MyApplication extends Application{
        private static MyApplication instance;
        public MyApplication(){
            instance = this;
        }
        public static Context getContext(){
            return instance;
        }
    }
    
    public class LocalDBHelper extends SQLiteOpenHelper{
        private static final int DATABASE_VERSION = 1;
        private static final String DATABASE_NAME = "MyDB";
        private static final String LOG_TAG = "LocalDBHelper";
    
        private static LocalDBHelper instance = null;
        /*private constructor to avoid direct instantiation by other classes*/
        private LocalDBHelper(){
            super(MyApplication.getContext(), DATABASE_NAME, null, DATABASE_VERSION);
        }
        /*synchronized method to ensure only 1 instance of LocalDBHelper exists*/
        public static synchronized LocalDBHelper getInstance(){
            if(instance == null){
                instance = new LocalDBHelper();
            }
            return instance;
        }
        ...
        ...
    }
    

    用法:

    SQLiteDatabase db = LocalDBHelper.getInstance().getWritableDatabase();
    db.insert(...)
    

    用于交易:

    SQLiteDatabase db = LocalDBHelper.getInstance().getWritableDatabase();
    db.beginTransaction();
    try{
    ....
    ...
    db.setTransactionSuccessful();
    }catch(Exception e){
        e.printStackTrace();
    }
    finally{
        db.endTransaction();
    

    }

    重要提示:无需在任何地方拨打localDBHelper.getInstance().close()

    【讨论】:

      【解决方案3】:

      由于您的应用每次启动时都在同一台机器上运行,并且每次访问的内存都相同,因此打开它不会有问题。因为在相同的内存空间中,sqlite 就像主应用程序的 DLL 一样加载。

      可能只会出现一个问题!当您想同时运行多个线程来访问数据库时(例如使用 AsyncTask),它们之间的干扰会迫使一些线程停止!所以最好每次都为新线程建立连接!

      【讨论】:

      • 这很有趣。您认为在 Android 中打开 SQLite 连接是一项耗费资源/时间的操作吗?
      • @faizal 据我所知,操作系统为每个客户端连接都有一些缓冲区。因此分配和释放这些缓冲区需要时间。
      【解决方案4】:

      就我个人而言,我发现调用初始应用加载所需的 SQL 连接、存储到 SQLite DB 中以及设置刷新按钮让用户决定何时刷新数据或设置定期更新应用程序的间隔计时器。

      通过这种方式,您可以在应用程序的一般使用期间通过将数据加载放置在预先/用户定义的时间来提高性能。

      虽然我确实认为这取决于数据库交互执行的频率......

      这个问题可能会给你一些有用的答案:

      Should I open() and close() my SQL database constantly or leave it open?

      【讨论】:

      • 对不起,我意识到我的问题具有误导性,因此我对其进行了更改以使其更加清晰。如果应用程序中不涉及远程 SQL 访问,那么创建一个长期存在的本地 SQLite 连接是否有意义?
      • 好吧,如果没有远程 SQL 访问,我认为这不会是一个问题,但是如果应用程序在之前的活动中打开数据库时尝试在数据库上运行任何函数,它可能开始一两个错误。
      • 这里的一些答案可能对你有用:) stackoverflow.com/questions/6339545/…
      • 我认为跨活动不会有问题,因为我将关闭 onPause() 中的连接。
      • 啊,我明白了...老实说,我当时看不到任何问题,但也许其他用户可能有一些我不知道的见解:)
      猜你喜欢
      • 2018-05-17
      • 1970-01-01
      • 2017-02-23
      • 2013-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-16
      相关资源
      最近更新 更多