Рекомендации по повторному использованию IDbConnection или строки подключения / фабрики в вашем .Сетевой код

StackOverflow https://stackoverflow.com/questions/414207

Вопрос

Мне интересно, какова была бы наилучшая рекомендация относительно поддержания подключений к базе данных в .Сетевое приложение (ADO.NET но я предполагаю, что практика должна быть одинаковой для любого уровня данных).Должен ли я создать подключение к базе данных и распространить его по всему моему приложению, или было бы лучше просто передать строки подключения / фабрики и создать соединение ad-hoc, когда это необходимо.

Насколько я понимаю, снижение производительности не имеет существенного значения при объединении в пул, и это позволяет мне довольно легко восстанавливаться после разорванных подключений (будет создано просто новое соединение), но опять же, объект connection - это хорошая, относительно высокоуровневая абстракция, и создание нового соединения для каждой операции (не команды SQL, а операции приложения) генерирует дополнительный дублированный код и воспринимается как пустая трата времени / ресурсов (?).

Что вы думаете об этих двух случаях, каковы их минусы / плюсы и какой подход вы используете в своих реальных приложениях?

Спасибо

Это было полезно?

Решение

Я обнаружил, что мне нужно передать объект подключения, чтобы я мог разрешить нескольким бизнес-объектам сохранять себя в базе данных внутри одной транзакции.

Если бы каждый бизнес-объект должен был создавать свое собственное SqlConnection к базе данных, транзакция переросла бы в распределенную транзакцию, и я хотел избежать этого.

Мне не нравилось передавать объект SqlConnection в качестве параметра для сохранения объекта, поэтому я создал ConnectionManager, который обрабатывает создание объекта SqlConnection для меня, отслеживает использование объекта SqlConnection и отключает объект SqlConnection, когда он не используется.

Вот некоторый код в качестве примера ConnectionManager:

public class ConnectionManager: IDisposable
{
    private ConnectionManager instance;

    [ThreadStatic]
    private static object lockObject; 
    private static Object LockObject
    {
        get
        {
            if (lockObject == null)
                lockObject = new object();
            return lockObject;
        }
    }

    [ThreadStatic]
    private static Dictionary<string, ConnectionManager> managers;
    private static Dictionary<string, ConnectionManager> Managers
    {
        get
        {
            if (managers == null)
                managers = new Dictionary<string, ConnectionManager>();
            return managers;
        }
    }

    private SqlConnection connection = null;
    private int referenceCount;
    private string name;


    public static ConnectionManager GetManager(string connectionName)
    {
        lock (LockObject)
        {
            ConnectionManager mgr;
            if (Managers.ContainsKey(connectionName))
            {
                mgr = Managers[connectionName];
            }
            else
            {
                mgr = new ConnectionManager(connectionName);
                Managers.Add(connectionName, mgr);
            }

            mgr.AddRef();
            return mgr;
        }
    }

    private ConnectionManager(string connectionName)
    {
        name = connectionName;
        connection = new SqlConnection(GetConnectionString(connectionName));
        connection.Open();
    }

    private string GetConnectionString(string connectionName)
    {
        string conString = Configuration.ConnectionString;
        return conString; 
    }

    public SqlConnection Connection
    {
        get { return connection; }
    }

    private void AddRef()
    {
        referenceCount += 1;
    }

    private void DeRef()
    {
        lock (LockObject)
        {
            referenceCount -= 1;
            if (referenceCount == 0)
            {
                connection.Dispose();
                Managers.Remove(name);
            }
        }
    }

#region IDisposable Members

    public void Dispose()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            DeRef();
        }
    }

    ~ConnectionManager()
    {
        Dispose(false);
    }

#endregion

}

Вот как я бы использовал его из бизнес-объекта:

public void Save()
{   
    using (ConnectionManager mrg = ConnectionManager.GetManager("SQLConnectionString")
    {
        using (SQLCommand cmd = new SQLCommand)
        {
            cmd.connection = mgr.Connection
            // More ADO Code Here
        }

        _childObject.Save(); //this child object follows the same pattern with a using ConnectionManager.
    }
}

Я сохраняю бизнес-объект, и все его дочерние элементы также сохраняются, используя один и тот же объект подключения.Когда область действия отклоняется от исходного родительского элемента, оператор using закрывает соединение.

Этому шаблону я научился у Рокки Лхотки в его CSLA framework.

Кит

Другие советы

Вам действительно не следует решать эту проблему самостоятельно, поскольку существует бесчисленное множество инструментов, которые могут сделать это за вас.

Если вы действительно хотите сделать это сами, то загляните в Единица измерения работы шаблон, с помощью которого вы можете управлять жизненным циклом подключения / транзакции.Вы, конечно, не хотите пытаться ориентироваться в грязных водах, где в разных местах открываются / закрываются соединения.

Если вы решите разрешить своим компонентам напрямую открывать подключения к БД, то, вероятно, жизненный цикл подключения будет слишком детализированным и приведет к множеству открытых / закрытых подключений для одной пользовательской операции.

ADO.NET Поставщик SQL Server сам создает пул соединений.Вы можете контролировать размер пула с помощью MinPoolSize и MaxPoolSize в строке подключения.

Одна вещь, которой следует опасаться в вашем примере, заключается в том, что ASP.NET приложения не должны использовать ThreadStatic storage, так как поток может быть использован повторно, и если вы не очистите все свои объекты, то в конечном итоге у вас оборвется соединение.

В приложении ASP.NET я бы использовал вместо этого HttpContext.Коллекцию Items.Вы реализуете IDisposable, но я видел сценарии, в которых разработчики забывали вызвать Dispose или поместить код в блок using.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top