NOLOCKEntity Framework에서이 기능을 사용하려면 어떻게 해야합니까? XML이이를 수행 할 수있는 유일한 방법입니까?
NOLOCKEntity Framework에서이 기능을 사용하려면 어떻게 해야합니까? XML이이를 수행 할 수있는 유일한 방법입니까?
답변:
아니요, 그러나 트랜잭션을 시작하고 격리 수준을 커밋되지 않은 읽기로 설정할 수 있습니다 . 이것은 본질적으로 NOLOCK과 동일하지만 테이블 단위로 수행하는 대신 트랜잭션 범위 내의 모든 항목에 대해 수행합니다.
그것이 원하는 것처럼 들리면 다음과 같이하십시오.
//declare the transaction options
var transactionOptions = new System.Transactions.TransactionOptions();
//set it to read uncommited
transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
//create the transaction scope, passing our options in
using (var transactionScope = new System.Transactions.TransactionScope(
System.Transactions.TransactionScopeOption.Required,
transactionOptions)
)
//declare our context
using (var context = new MyEntityConnection())
{
//any reads we do here will also read uncomitted data
//...
//...
//don't forget to complete the transaction scope
transactionScope.Complete();
}
확장 방법으로 이것을 쉽게 만들 수 있습니다
public static List<T> ToListReadUncommitted<T>(this IQueryable<T> query)
{
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions() {
IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
List<T> toReturn = query.ToList();
scope.Complete();
return toReturn;
}
}
public static int CountReadUncommitted<T>(this IQueryable<T> query)
{
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions() {
IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
int toReturn = query.Count();
scope.Complete();
return toReturn;
}
}
큰 무언가가 필요한 경우 실제로 매번 transactionscope를 시작하는 것보다 덜 방해가되는 가장 좋은 방법은 다음 간단한 명령을 실행하여 객체 컨텍스트를 만든 후 연결에서 기본 트랜잭션 격리 수준을 설정하는 것입니다.
this.context.ExecuteStoreCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
http://msdn.microsoft.com/en-us/library/aa259216(v=sql.80).aspx
이 기술을 사용하여 컨텍스트를 작성하고 모든 컨텍스트에 대해 매번이 명령을 실행하여 기본적으로 항상 "커밋되지 않은 읽기"상태가되도록하는 간단한 EF 제공자를 작성할 수있었습니다.
Transactions running at the READ UNCOMMITTED level do not issue shared locks. 즉, 혜택을 받으려면 트랜잭션 내에서 실행 중이어야합니다. ( msdn.microsoft.com/en-gb/library/ms173763.aspx 에서 가져옴 ). 접근 방식이 덜 어려울 수 있지만 트랜잭션을 사용하지 않으면 아무것도 달성되지 않습니다.
SET TRANSACTION ISOLATION LEVEL...명령은 연결 레벨 특성에 영향을 미치므로 조회 힌트로 대체되지 않는 한 해당 시점부터 작성된 모든 SQL 문 (THAT 연결의 경우)에 영향을줍니다. 이 동작은 적어도 SQL Server 2000 이후로 발생했으며 이전에는 가능했을 것입니다.
CREATE TABLE ##Test(Col1 INT); BEGIN TRAN; SELECT * FROM ##Test WITH (TABLOCK, XLOCK);. 다른 쿼리 (# 2)를 열고 다음을 실행하십시오 SELECT * FROM ##Test;. 단독 잠금을 사용하는 탭 # 1의 여전히 열린 트랜잭션에 의해 차단되고 있으므로 SELECT가 반환되지 않습니다. # 2에서 SELECT를 취소하십시오. SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED탭 # 2에서 한 번 실행하십시오 . 탭 # 2에서 SELECT 만 다시 실행하면 다시 나타납니다. ROLLBACK탭 # 1에서 실행해야합니다 .
커밋되지 않은 읽기 트랜잭션 격리 수준을 사용하는 것이 최선의 선택이라는 데 전적으로 동의했지만 언젠가는 관리자 또는 클라이언트의 요청에 따라 NOLOCK 힌트를 사용해야했으며 이에 대한 이유도 없었습니다.
Entity Framework 6을 사용하면 다음과 같이 자체 DbCommandInterceptor를 구현할 수 있습니다.
public class NoLockInterceptor : DbCommandInterceptor
{
private static readonly Regex _tableAliasRegex =
new Regex(@"(?<tableAlias>AS \[Extent\d+\](?! WITH \(NOLOCK\)))",
RegexOptions.Multiline | RegexOptions.IgnoreCase);
[ThreadStatic]
public static bool SuppressNoLock;
public override void ScalarExecuting(DbCommand command,
DbCommandInterceptionContext<object> interceptionContext)
{
if (!SuppressNoLock)
{
command.CommandText =
_tableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH (NOLOCK)");
}
}
public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
if (!SuppressNoLock)
{
command.CommandText =
_tableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH (NOLOCK)");
}
}
}
이 클래스를 사용하면 응용 프로그램 시작시 적용 할 수 있습니다.
DbInterception.Add(new NoLockInterceptor());
그리고 NOLOCK현재 스레드에 대한 쿼리 에 힌트 추가를 조건부로 해제하십시오 .
NoLockInterceptor.SuppressNoLock = true;
public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { if (!SuppressNoLock) command.CommandText = $"SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;{Environment.NewLine}{command.CommandText}"; base.ReaderExecuting(command, interceptionContext); }
닥터 존스 의 대답을 향상 시키고 PostSharp 사용 ;
첫 번째 " ReadUncommitedTransactionScopeAttribute "
[Serializable]
public class ReadUncommitedTransactionScopeAttribute : MethodInterceptionAspect
{
public override void OnInvoke(MethodInterceptionArgs args)
{
//declare the transaction options
var transactionOptions = new TransactionOptions();
//set it to read uncommited
transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted;
//create the transaction scope, passing our options in
using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
{
//declare our context
using (var scope = new TransactionScope())
{
args.Proceed();
scope.Complete();
}
}
}
}
그런 다음 필요할 때마다
[ReadUncommitedTransactionScope()]
public static SomeEntities[] GetSomeEntities()
{
using (var context = new MyEntityConnection())
{
//any reads we do here will also read uncomitted data
//...
//...
}
}
인터셉터로 "NOLOCK"을 추가 할 수 있다는 것도 좋지만 Oracle과 같은 다른 데이터베이스 시스템에 연결할 때는 작동하지 않습니다.
EF6이 도입되면 BeginTransaction () 메서드를 사용하는 것이 좋습니다.
EF6 + 및 EF Core에서 TransactionScope 대신 BeginTransaction을 사용할 수 있습니다.
using (var ctx = new ContractDbContext())
using (var transaction = ctx.Database.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted))
{
//any reads we do here will also read uncommitted data
}
아닙니다. Entity Framework는 기본적으로 실제 데이터베이스보다 상당히 엄격한 계층입니다. 쿼리는 먼저 엔터티 모델을 대상으로하는 ESQL (Entity SQL)로 구성되며 EF는 여러 데이터베이스 백엔드를 지원하므로 실제로 "네이티브"SQL을 백엔드로 직접 보낼 수는 없습니다.
NOLOCK 쿼리 힌트는 SQL Server 고유의 것으로 다른 지원되는 데이터베이스에서는 작동하지 않습니다 (동일한 힌트를 구현하지 않은 한 강력하게 의심합니다).
마크
Database.ExecuteSqlCommand()또는 DbSet<T>.SqlQuery().
(NOLOCK)어쨌든 - 볼 킥에 나쁜 습관 - 모든 지역 NOLOCK 퍼팅 -이되는 권장되지 사방이 사용하는 - 매우 반대!