Melhores práticas está compartilhando IDbConnection ou conexão corda / fábrica em seu código .Net

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

Pergunta

Eu estou querendo saber qual seria a melhor prectice sobre mainataining conexões com o banco de dados no aplicativo .NET (ADO.NET mas eu acho que a prática deve ser o mesmo para qualquer camada de dados). Devo criar uma conexão de banco de dados e propagá-lo ao longo da minha aplicação, ou seria melhor apenas para passar de conexão cordas / fábricas e criar um ad-hoc de conexão, quando for necessário.

Como eu entendo perfomance hit não é signifcant com pooling e me permite recuperar de conexões quebradas com bastante facilidade (basta uma nova conexão será criada) mas, novamente um objeto de conexão é um agradável, relativamente abstração de alto nível e criar uma nova conexão para cada operação (comando não SQL, mas a operação do aplicativo) gera código adicional, duplicado e se sente como um desperdício de tempo / recursos (?).

O que você acha sobre esses 2 casos, quais são as suas CONS / prós e qual a abordagem que você está usando em suas aplicações na vida real?

Graças

Foi útil?

Solução

Eu me vi na necessidade de passar em torno de um objeto de conexão para que eu pudesse permitir que vários objetos de negócios para salvar-se ao banco de dados dentro de uma única transação.

Se cada objeto de negócios tiveram que criar o seu próprio SQLConnection ao banco de dados, a operação iria escalar para uma transação distribuída e eu queria evitar isso.

eu não gosto de ter que passar o objeto SQLConnection como parâmetro para salvar um objeto, então eu criei um ConnectionManager que lida com a criação do objeto SQLConnection para mim, o rastreamento do uso do objeto SQLConnection, e desconectar o objeto SQLConnection quando não em uso.

Aqui está um código como um exemplo do 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

}

Aqui está como eu iria utilizá-lo a partir de um objeto de negócios:

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

Eu salvar um objeto de negócios e todos os seus filhos são salvos como bem usando o mesmo objeto de conexão. Quando o escopo cai longe do pai original, a instrução usando fecha a conexão.

Este é um padrão que aprendi com Rocky Lhotka em seu quadro CSLA.

Keith

Outras dicas

Você realmente não deve ser lidar com o problema sozinho, uma vez que existem inúmeras ferramentas para fora lá que pode fazer isso por você.

Se você realmente deseja fazê-lo sozinho, então olhar para Unidade de padrão de trabalho o onde você pode gerenciar o ciclo de vida de conexão / transação. Você certamente não quer tentar navegar nas águas desarrumado onde há conexões a ser aberto / fechado em lugares diferentes.

Se você decidir deixar seus componentes conexões db diretamente abertos, então é provável que o ciclo de vida de conexão será muito refinada e resultar em muitas conexões abertas / fechadas para uma única operação do usuário.

provedor

ADO.NET SQL Server faz o pool de conexão em si. Você pode controlar o tamanho da piscina por MinPoolSize e MaxPoolSize na cadeia de conexão.

Uma coisa a ser cauteloso no seu exemplo é que os aplicativos ASP.NET não deve usar o armazenamento ThreadStatic, como um fio pode ser reutilizado, e se você não limpar todos os seus objetos que você acabar com um enforcamento conexão ao redor.

Em um aplicativo ASP.NET que eu usaria a coleção HttpContext.Items vez. Você está implementando IDisposable, mas eu vi cenários onde devs se esqueça de chamar Dispose ou colocar o código em um bloco usando.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top