确保Singleton只调用一次db查询

时间:2013-02-18 08:47:14

标签: c# singleton

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

我已经创建了类:

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<string> _mySettings;
    private static readonly Lazy<SettingsManager> _instance = new Lazy<SettingsManager>(() => 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<string> 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<T> Select<T>(
        this SqlDataReader reader, Func<SqlDataReader, T> 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)

3 个答案:

答案 0 :(得分:2)

  

1)这个线程安全吗?

  

DB有多少次查询?

没有

  

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

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

答案 1 :(得分:1)

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)如果您想要对数据库进行异步访问,则依赖它。

答案 2 :(得分:1)

  
      
  1. 这个线程安全吗?
  2.   

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

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

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

您可以使用名为asyncoriginally developed by Stephen Toubincluded in my AsyncEx libraryLazy<T>就绪版AsyncLazy<T>