當使用客戶機框架,ORM或類似的構建查詢(不支持查詢提示,如WITH(NOLOCK))時,爲各個事務實現不同隔離級別的最佳方式是什麼? ?假設一個應用程序使用ReadUncommitted級別進行一些複雜和長時間運行的查詢(瞭解相關風險),並且它應該與NHibernate一起運行並且它的查詢條件(或QueryOver/LINQ,只是沒有字符串級聯!)。僅在單個ADO.NET事務中更改隔離級別
NHibernate不支持with(nolock)提示(除非使用本機SQL,目前在許多情況下使用)。
因此,爲了替換本機SQL字符串及其繁瑣的構建代碼,我想使用IsolationLevel.ReadUncommitted事務來替換'with(nolock)'。
但是即使在提交/回滾之後,連接仍保持在更改的隔離級別中,從而在新級別運行所有內容。即使在connection.Close()之後,它也會返回到連接池並在更改後的隔離級別重用。
我最初注意到了這一點,因爲我測試了打開與快照隔離級別的連接併發送一個簡單的查詢,以在數據庫上啓用快照模式時禁用讀未提交(一般情況下無法輕鬆切換到快照)。測試數據庫禁用了快照模式,所以我得到一個異常並在catch塊中將我的UseReadUncommitted變量設置爲'true',但後來來自「新」/重用連接的查詢仍然得到相同的異常。
我寫了一個簡單的類來封裝使用塊中的事務處理,自動重置.Dispose()中的IsolationLevel。但是這似乎會給數據庫帶來兩個額外的往返行程,而且我不確定更改的隔離級別是否可以在某些情況下「存活」處置並影響其他查詢。代碼在第一次嘗試中工作,它用於純ADO.NET連接/事務(如果好的話,我會爲NHibernate會話做另一次)。
有什麼建議嗎?
public class TransactionContainerTempIsolationLevel : IDisposable
{
public IsolationLevel OldIsolationLevel { get; private set; }
public IsolationLevel TempIsolationLevel { get; private set; }
public IDbTransaction Transaction { get; private set; }
private readonly IDbConnection _conn;
public TransactionContainerTempIsolationLevel(IDbConnection connection, IsolationLevel tempIsolationLevel)
{
_conn = connection;
LocalIsolationLevel = localIsolationLevel;
var checkTran = _conn.BeginTransaction();
if (checkTran.IsolationLevel == tempIsolationLevel)
{
Transaction = checkTran;
}
else
{
OldIsolationLevel = checkTran.IsolationLevel;
checkTran.Dispose();
Transaction = _conn.BeginTransaction(tempIsolationLevel);
}
}
public void Dispose()
{
Transaction.Dispose();
if (OldIsolationLevel != TempIsolationLevel)
{
using (var restoreTran = _conn.BeginTransaction(OldIsolationLevel))
{
restoreTran.Commit();
}
}
}
}
如果隔離級別不匹配,您似乎回滾事務。 – usr
如果不應該回退,則主事務必須在Transaction屬性上顯式提交,就像任何事務一樣。 CheckTran只是獲取默認/當前隔離級別(如果默認級別匹配所需的隔離級別,它將用作主事務)。 –
當我發表評論時,不確定我在想什麼。 – usr