为啥 Xamarin 文档建议使用单例进行数据库连接?

Posted

技术标签:

【中文标题】为啥 Xamarin 文档建议使用单例进行数据库连接?【英文标题】:Why does Xamarin documentation suggest using singleton for database connection?为什么 Xamarin 文档建议使用单例进行数据库连接? 【发布时间】:2017-08-09 17:38:36 【问题描述】:

我正在查看 Xamarin 的官方文档,他们似乎鼓励使用静态/单例进行数据库连接,这对我来说似乎很奇怪:

这里https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/dependency-service/introduction/

这种方法会创建一个保持打开状态的单一数据库连接 在应用程序运行时,因此避免了打开的费用 并在每次数据库操作时关闭数据库文件 执行。 静态 TodoItemDatabase 数据库;

public static TodoItemDatabase Database

  get
  
    if (database == null)
    
      database = new TodoItemDatabase(DependencyService.Get<IFileHelper>().GetLocalFilePath("TodoSQLite.db3"));
    
    return database;
  

这里 https://developer.xamarin.com/guides/cross-platform/application_fundamentals/building_cross_platform_applications/part_2_-_architecture/

Singleton——Singleton 模式提供了一种方式,其中只有一个 特定对象的单个实例可能永远存在。例如, 在移动应用程序中使用 SQLite 时,您只需要一个 数据库的实例。使用单例模式是一种简单的方法 以确保这一点。

这里https://developer.xamarin.com/guides/cross-platform/application_fundamentals/building_cross_platform_applications/case_study-tasky/

TaskItemDatabase 是一个单例,确保所有访问都针对同一个实例。锁用于防止并发 多线程访问。

public T GetItem<T> (int id) where T : BL.Contracts.IBusinessEntity, new ()

    lock (locker) 
        return Table<T>().FirstOrDefault(x => x.ID == id);
    

在我看来,一般来说,这是一个广受劝阻的想法,例如在 SO 上: getting db connection through singleton class Is singleton approach right for accessing/maintaining database and internet connection

那么,知道为什么 Xamarin 团队会推广这种方法吗?是因为它们的框架的某些特殊性而有所不同吗? 更重要的是,如果不是这样,那么正确的方法是什么?

【问题讨论】:

【参考方案1】:

SQLite 数据库结构是您内存中的单个文件(您将其路径设置为“TodoSQLite.db3”)。可以将其想象为从代码的多个位置访问特定的 .txt 文件。

而不是使用锁定功能处理不同的连接(因为您不能同时运行多个操作),共享相同的连接实例更便宜且更清洁,这就是单例。

【讨论】:

我喜欢这个答案。由于这不是提问者可以验证答案是否确实正确的问题,所以我现在只投赞成票。我将重新审视这个问题,如果它得到更多票数,我会将其标记为正确答案。 不要使用锁定功能。相反,请使用异步 API。【参考方案2】:

Xamarin 最流行的 SQLite ORM SQLite-net 是线程安全的,可以为您处理数据库连接。

我更喜欢用类似的方式构建我的数据库,使用检索连接的BaseDatabase 类。

基础数据库

注意 BaseDatabase 使用Xamarin.Essentials NuGet Package 来定位应用的数据目录。请务必先添加 Xamarin.Essentials NuGet 包并关注Getting Started Instructions。

using System.Threading.Tasks;

using SQLite;

using Xamarin.Essentials;
using Xamarin.Forms;

namespace MyNamespace

    public abstract class BaseDatabase
    
        static readonly string _databasePath = Path.Combine(FileSystem.AppDataDirectory, "SqliteDatabase.db3");
        static readonly Lazy<SQLiteAsyncConnection> _databaseConnectionHolder = new Lazy<SQLiteAsyncConnection>(() => new SQLiteAsyncConnection(_databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.SharedCache));

        SQLiteAsyncConnection DatabaseConnection => _databaseConnectionHolder.Value;

        protected static async Task<SQLiteAsyncConnection> GetDatabaseConnection<T>()
        
            if (!DatabaseConnection.TableMappings.Any(x => x.MappedType.Name == typeof(T).Name))
            
                // On sqlite-net v1.6.0+, enabling write-ahead logging allows for faster database execution
                // await DatabaseConnection.EnableWriteAheadLoggingAsync().ConfigureAwait(false);
                await DatabaseConnection.CreateTablesAsync(CreateFlags.None, typeof(T)).ConfigureAwait(false);
            

            return DatabaseConnection;
            
    

数据库

namespace MyNamespace

    public class OpportunityModelDatabase : BaseDatabase
    
        public async Task<List<OpportunityModel>> GetAllOpportunityDataAsync()
        
            var databaseConnection = await GetDatabaseConnection<OpportunityModel>().ConfigureAwait(false);

            return await databaseConnection.Table<OpportunityModel>().ToListAsync().ConfigureAwait(false);
        
    

【讨论】:

我不确定我是否理解您的实现。你开始很好,我和你在一起,但是在你的初始化方法中,你明确地声明了 OpportunityModel。为什么这样做而不是泛型?除非您打算将该空间留作所有表格的 CreateTable?如果不是,我不明白你为什么要费心把它抽象出来,还不如直接把它放在 OpportunityModelDatabase 类中,因为没有其他东西可以使用它吗? 很好,@Phil!我更新了答案以使用 GetDatabaseConnection() 的泛型类型。

以上是关于为啥 Xamarin 文档建议使用单例进行数据库连接?的主要内容,如果未能解决你的问题,请参考以下文章

为啥滚动这个 xamarin 页面这么慢?

为啥 MongoDB 文档建议不要使用 DBREF?

单例设计模式全局缓存accessToken

为啥 Hibernate 文档建议将连接表用于一对多关系?

通过USB连接到Xamarin.Android应用程序与网站进行通信

为啥手机连WIFI能上的网站,连4G就无法进入?