为啥 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 文档建议使用单例进行数据库连接?的主要内容,如果未能解决你的问题,请参考以下文章