确保Singleton只调用一次db查询

我正在尝试创建一个负责读取所有用户访问设置的对象。

我已经创建了这样的类:

public class SettingsManager { private static string _connString = @"Data Source=MyDB;Initial Catalog=IT;Integrated Security=True;Asynchronous Processing=true;"; private const string _spName = "SettingTest"; private IEnumerable _mySettings; private static readonly Lazy _instance = new Lazy(() => new SettingsManager()); private SettingsManager() { //Console.WriteLine("Hello from constructor"); if (_mySettings == null) _mySettings = ReadSettings(); } public static SettingsManager Instance { get { return _instance.Value; } } public bool CanDo(string setting) { return _mySettings.Contains(setting); } private IEnumerable ReadSettings() { try { using (var conn = new SqlConnection(_connString)) { using (var cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandText = _spName; cmd.CommandType = CommandType.StoredProcedure; conn.Open(); using (var reader = cmd.ExecuteReader()) { return reader.Select(SettingParser).ToList(); } } } } catch { } return null; } private string SettingParser(SqlDataReader r) { try { return r[0] is DBNull ? null : r[0].ToString(); } catch { } return null; } } 

和SqlDataReader扩展

 public static class DBExtensions { public static IEnumerable Select( this SqlDataReader reader, Func projection) { while (reader.Read()) { yield return projection(reader); } } } 

然后在我的应用程序中,我可以这样称呼它:

 SettingsManager.Instance.CanDo("canWrite") 

返回true / false值取决于用户访问级别。

我的问题是:

  1. 这个线程安全吗? 有没有机会DB多次查询? 怎么预防这个?

  2. 我应该使用await和async吗? 我只查询一次db。 我怎样才能改善这个? (await和async对我来说真的很新,因为我刚刚从.NET3.5迁移到4.5)

1)这个线程安全吗?

是。

有没有机会DB多次查询?

没有。

2)我应该使用await和async吗?

这取决于您是否需要异步访问数据库。 如果需要,可以使用异步ADO.NET API。

1)是的,这是线程安全的

线程安全的Singleton:这个实现使用内部类使.NET实例化完全懒惰。 只有GetInstance()会触发类型初始值设定项; 所以,这个版本和经典版一样懒。 并且,它将像任何其他版本一样快速地执行。

 public sealed class Singleton { private Singleton() {} public static Singleton GetInstance() { return NestedSingleton.singleton; } class NestedSingleton { internal static readonly Singleton singleton = new Singleton(); static NestedSingleton() {} } } 

2)这取决于您是否希望异步访问您的数据库。

  1. 这个线程安全吗?

是。 您正确使用Lazy类型以确保线程安全。

  1. 我应该使用await和async吗?

我会推荐它。 现在,第一次应用程序代码调用SettingsManager.Instance.CanDo("canWrite") ,它将一直阻塞,直到DB响应。 您也可以在消费者可以进行async实现(await SettingsManager.Instance).CanDo("canWrite") (或await SettingsManager.CanDoAsync("canWrite") )。 这意味着您的消费者在等待数据库时不会阻止。

您可以使用最初由Stephen Toub开发并包含在我的AsyncEx库中的名为AsyncLazy版本的Lazy