使用SqlConnection / System.Transactions進行會話請求

dapper sqlconnection sql-server system.transactions

我剛剛開始使用Dapper進行一個項目,過去幾年里大多使用像NHibernate和EF這樣的ORM。

通常在我們的Web應用程序中,我們按請求實現會話,在請求開始時開始事務並在結束時提交它。

我們應該在直接使用SqlConnection / System.Transactions時做類似的事情嗎?

StackOverflow如何做到這一點?

根據@gbn和@Sam Safron的建議,我沒有使用交易。在我的情況下,我只是在進行讀取查詢,所以似乎沒有真正的要求使用事務(與我所知道的隱式事務相反)。

我創建了一個輕量級的會話接口,以便每個請求都可以使用一個連接。這對我來說非常有益,因為對於Dapper我經常需要創建一些不同的查詢來構建一個對象,而寧願共享相同的連接。

確定每個請求的連接並處理它的工作是由我的IoC容器(StructureMap)完成的:

public interface ISession : IDisposable {
    IDbConnection Connection { get; }
}

public class DbSession : ISession {

    private static readonly object @lock = new object();
    private readonly ILogger logger;
    private readonly string connectionString;
    private IDbConnection cn;

    public DbSession(string connectionString, ILogger logger) {
        this.connectionString = connectionString;
        this.logger = logger;
    }

    public IDbConnection Connection { get { return GetConnection(); } }

    private IDbConnection GetConnection() {
        if (cn == null) {
            lock (@lock) {
                if (cn == null) {
                    logger.Debug("Creating Connection");
                    cn = new SqlConnection(connectionString);
                    cn.Open();
                    logger.Debug("Opened Connection");
                }
            }
        }

        return cn;
    }

    public void Dispose() {
        if (cn != null) {
            logger.Debug("Disposing connection (current state '{0}')", cn.State);
            cn.Dispose();
        }
    }
}

一般承認的答案

這就是我們的工作:

我們在名為Current對像上定義一個名為DB的靜態

public static DBContext DB
{
    var result = GetContextItem<T>(itemKey);

    if (result == null)
    {
        result = InstantiateDB();
        SetContextItem(itemKey, result);
    }

    return result;
}

public static T GetContextItem<T>(string itemKey, bool strict = true)
{

#if DEBUG // HttpContext is null for unit test calls, which are only done in DEBUG
    if (Context == null)
    {
        var result = CallContext.GetData(itemKey);
        return result != null ? (T)result : default(T);
    }
    else
    {
#endif
        var ctx = HttpContext.Current;
        if (ctx == null)
        {
            if (strict) throw new InvalidOperationException("GetContextItem without a context");
            return default(T);
        }
        else
        {
            var result = ctx.Items[itemKey];
            return result != null ? (T)result : default(T);
        }
#if DEBUG
    }
#endif
}

public static void SetContextItem(string itemKey, object item)
{
#if DEBUG // HttpContext is null for unit test calls, which are only done in DEBUG
    if (Context == null)
    {
        CallContext.SetData(itemKey, item);
    }
    else
    {
#endif
        HttpContext.Current.Items[itemKey] = item;

#if DEBUG
    }
#endif
}

在我們的例子中, InstantiateDB返回一個L2S上下文,但在你的情況下它可能是一個開放的SQLConnection或其他。

在我們的應用程序對像上,我們確保在請求結束時關閉連接。

   protected void Application_EndRequest(object sender, EventArgs e)
   {
        Current.DisposeDB(); // closes connection, clears context 
   }

然後在您的代碼中您需要訪問數據庫的任何地方,您可以簡單地調用Current.DB並自動運行。由於所有#if DEBUG東西,這也是單元測試友好的。


我們不會在每個會話中啟動任何事務,如果我們在會話開始時進行了更新,那麼我們就會遇到嚴重的鎖定問題,因為鎖定不會在最後發布。


熱門答案

當你需要的東西,如你只啟動一個SQL Server事務TransactionScope的 ,當你調用一個“寫”調用數據庫。

請參閱最近這個問題中的一個隨機示例: 為什麼即使從未調用TransactionScope.Complete(),也會提交嵌套事務?

不會打開連接並按http請求啟動事務。只有按需。我很難理解為什麼有些人提倡每次會話打開一個數據庫事務:當你看一下數據庫事務是什麼時,純粹是白痴

注意:我不反對模式本身。我反對調用MSDTC的不必要的,太長的客戶端數據庫事務



許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因