【问题标题】: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 团队会推广这种方法吗?是因为它们的框架的某些特殊性而有所不同吗? 更重要的是,如果不是这样,那么正确的方法是什么?

【问题讨论】:

    标签: c# sqlite xamarin mobile singleton


    【解决方案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() 的泛型类型。
    猜你喜欢
    • 2017-04-07
    • 2021-09-23
    • 1970-01-01
    • 2013-06-22
    • 2014-07-03
    • 2016-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多