EF6를 사용하면 다음과 같이 사용할 수있는 새 트랜잭션이 있습니다.
using (var context = new PostEntityContainer())
{
using (var dbcxtransaction = context.Database.BeginTransaction())
{
try
{
PostInformation NewPost = new PostInformation()
{
PostId = 101,
Content = "This is my first Post related to Entity Model",
Title = "Transaction in EF 6 beta"
};
context.Post_Details.Add(NewPost);
context.SaveChanges();
PostAdditionalInformation PostInformation = new PostAdditionalInformation()
{
PostId = (101),
PostName = "Working With Transaction in Entity Model 6 Beta Version"
};
context.PostAddtional_Details.Add(PostInformation);
context.SaveChanges();
dbcxtransaction.Commit();
}
catch
{
dbcxtransaction.Rollback();
}
}
}
일이 옆으로 갈 때 롤백이 실제로 필요합니까? Commit 설명에 “기본 저장소 트랜잭션을 커밋합니다.”라고 나와 있기 때문에 궁금합니다.
롤백 설명은 “기본 저장소 트랜잭션을 롤백합니다.”라고 말합니다.
이것은 Commit이 호출되지 않으면 이전에 실행 된 명령이 저장되지 않을 것으로 보이므로 궁금합니다. 하지만 그렇다면 Rollback 함수를 호출하는 이유는 무엇일까요? EF5에서는 논리적으로 보이는 롤백 기능 (완료 만 해당)이없는 TransactionScope를 사용했습니다. MS DTC 이유로 인해 TransactionScope를 더 이상 사용할 수 없지만 위의 예와 같은 try catch를 사용할 수 없습니다 (즉, Commit 만 필요함).
답변
문을 Rollback
사용하고 있으므로 수동으로 호출 할 필요가 없습니다 using
.
DbContextTransaction.Dispose
메소드는 using
블록 의 끝에서 호출됩니다 . 그리고 트랜잭션이 성공적으로 커밋되지 않은 경우 (호출되지 않거나 예외가 발생하면) 트랜잭션을 자동으로 롤백합니다. 다음은 SqlInternalTransaction.Dispose
메서드 의 소스 코드입니다 ( DbContextTransaction.Dispose
SqlServer 공급자를 사용할 때 마지막으로 위임 됨).
private void Dispose(bool disposing)
{
// ...
if (disposing && this._innerConnection != null)
{
this._disposing = true;
this.Rollback();
}
}
_innerConnection
null이 아닌지 확인 하고 그렇지 않은 경우 트랜잭션을 롤백합니다 (커밋 된 경우 _innerConnection
null이 됨). 무엇을하는지 보자 Commit
:
internal void Commit()
{
// Ignore many details here...
this._innerConnection.ExecuteTransaction(...);
if (!this.IsZombied && !this._innerConnection.IsYukonOrNewer)
{
// Zombie() method will set _innerConnection to null
this.Zombie();
}
else
{
this.ZombieParent();
}
// Ignore many details here...
}
internal void Zombie()
{
this.ZombieParent();
SqlInternalConnection innerConnection = this._innerConnection;
// Set the _innerConnection to null
this._innerConnection = null;
if (innerConnection != null)
{
innerConnection.DisconnectTransaction(this);
}
}
답변
항상 EF와 함께 SQL Server를 사용하는 경우에는 catch를 명시 적으로 사용하여 Rollback 메서드를 호출 할 필요가 없습니다. using 블록이 모든 예외에 대해 자동으로 롤백하도록 허용하면 항상 작동합니다.
그러나 Entity Framework 관점에서 생각해 보면 모든 예제에서 명시 적 호출을 사용하여 트랜잭션을 롤백하는 이유를 알 수 있습니다. EF에게 데이터베이스 공급자는 임의적이고 플러그 가능하며 공급자는 MySQL 또는 EF 공급자 구현이있는 다른 데이터베이스로 대체 될 수 있습니다. 따라서 EF의 관점에서 볼 때 EF는 데이터베이스 공급자의 구현에 대해 알지 못하기 때문에 공급자가 삭제 된 트랜잭션을 자동으로 롤백 할 것이라는 보장이 없습니다.
따라서 모범 사례로 EF 문서에서는 언젠가 공급자를 폐기시 자동 롤백하지 않는 구현으로 변경하는 경우에 대비하여 명시 적으로 롤백 할 것을 권장합니다.
제 생각에는 훌륭하고 잘 작성된 공급자는 처리에서 트랜잭션을 자동으로 롤백하므로 try-catch-rollback을 사용하여 using 블록 내부의 모든 것을 래핑하려는 추가 노력이 과도합니다.
답변
- 트랜잭션을 인스턴스화하기 위해 ‘using’블록을 작성 했으므로 롤백 함수는 처리시 자동으로 롤백되므로 명시 적으로 언급 할 필요가 없습니다 (커밋되지 않은 경우).
- 그러나 using 블록없이 인스턴스화하는 경우 예외 (정확히 catch 블록에서)의 경우 트랜잭션을 롤백하고 더 강력한 코드를위한 null 검사를 사용하여 트랜잭션을 롤백해야합니다. BeginTransaction의 작동은 트랜잭션 범위와 다릅니다 (모든 작업이 성공적으로 완료된 경우 완전한 기능 만 필요함). 대신 SQL 트랜잭션의 작동과 유사합니다.