Ensure Singleton call db query only once

时光怂恿深爱的人放手 提交于 2019-12-07 11:45:28

问题


I'm trying to create one object that will be responsible for reading all users access settings.

I've created class as so:

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;
    }
}

And SqlDataReader Extension

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

Then inside my application I'm able to call it as so:

SettingsManager.Instance.CanDo("canWrite")

this returns true/false value depends on user access level.

My questions are:

  1. Is this thread safe? Are there any chances DB will be query multiple times? How to prevent this?

  2. Should I use await and async? I query db just once. How can I improve this? (await and async are really new to me because I just moved from .NET3.5 to 4.5)


回答1:


1) Is this thread safe?

Yes.

Are there any chances DB will be query multiple times?

No.

2) Should I use await and async?

That will depend on whether you need asynchronous access to your database. If you need that you could use the async ADO.NET API.




回答2:


1)yes this is, thread safe

Thread-safe Singleton: This implementation uses an inner class to make the .NET instantiation fully lazy. Only GetInstance() will trigger the type initializer; so, this version is just as lazy as the classic version. And, it will perform as quckly as any other version.

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)It's depend if you want asynchronous access to your DB.




回答3:


  1. Is this thread safe?

Yes. You are using the Lazy<T> type correctly to ensure thread-safety.

  1. Should I use await and async?

I would recommend it. Right now, the first time your application code calls SettingsManager.Instance.CanDo("canWrite"), it will block until the DB responds. It's also possible to have an async implementation where your consumers could do (await SettingsManager.Instance).CanDo("canWrite") (or await SettingsManager.CanDoAsync("canWrite")). This means your consumers do not block while waiting for the DB.

You can use an async-ready version of Lazy<T> called AsyncLazy<T>, originally developed by Stephen Toub and included in my AsyncEx library.



来源:https://stackoverflow.com/questions/14932387/ensure-singleton-call-db-query-only-once

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!