确保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值取决于用户访问级别。
我的问题是:
-
这个线程安全吗? 有没有机会DB多次查询? 怎么预防这个?
-
我应该使用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)这取决于您是否希望异步访问您的数据库。
- 这个线程安全吗?
是。 您正确使用Lazy
类型以确保线程安全。
- 我应该使用await和async吗?
我会推荐它。 现在,第一次应用程序代码调用SettingsManager.Instance.CanDo("canWrite")
,它将一直阻塞,直到DB响应。 您也可以在消费者可以进行async
实现(await SettingsManager.Instance).CanDo("canWrite")
(或await SettingsManager.CanDoAsync("canWrite")
)。 这意味着您的消费者在等待数据库时不会阻止。
您可以使用最初由Stephen Toub开发并包含在我的AsyncEx库中的名为AsyncLazy
版本的Lazy
。