[global::System.AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class TransactionAttribute : Attribute
{
}
public class ServicesInterceptor : Castle.Core.Interceptor.IInterceptor
{
private readonly ISession db;
private ITransaction transaction = null;
public ServicesInterceptor(ISession db)
{
this.db = db;
}
public void Intercept(IInvocation invocation)
{
ILog log = LogManager.GetLogger(string.Format("{0}.{1}", invocation.Method.DeclaringType.FullName, invocation.Method.Name));
bool isTransactional = IsTransactional(invocation.Method);
bool iAmTheFirst = false;
if (transaction == null && isTransactional)
{
transaction = db.BeginTransaction();
iAmTheFirst = true;
}
try
{
invocation.Proceed();
if (iAmTheFirst)
{
iAmTheFirst = false;
transaction.Commit();
transaction = null;
}
}
catch (Exception ex)
{
if (iAmTheFirst)
{
iAmTheFirst = false;
transaction.Rollback();
db.Clear();
transaction = null;
}
log.Error(ex);
throw ex;
}
}
private bool IsTransactional(MethodInfo mi)
{
var atrClass = mi.DeclaringType.GetCustomAttributes(false);
foreach (var a in atrClass)
if (a is TransactionAttribute)
return true;
var atrMethod = mi.GetCustomAttributes(false);
foreach (var a in atrMethod)
if (a is TransactionAttribute)
return true;
return false;
}
}
Iはautofacを使用する場合、私は同じ容器を使用する方法はスコープではなく、私のリポジトリ/ DAOオブジェクトに同じセッションを渡す私は、コンテナがスコープされたUnitOfWorkを渡します。作業ユニットはコンストラクターにこれを持っています。
private readonly ISession _session;
private ITransaction _transaction;
public UnitOfWork(ISession session)
{
_session = session;
_transaction = session.BeginTransaction();
}
処分している:
public void Dispose()
{
try
{
if (_transaction != null &&
!_transaction.WasCommitted &&
!_transaction.WasRolledBack)
_transaction.Commit();
_transaction = null;
}
catch (Exception)
{
Rollback();
throw;
}
}
私は(AB)これを管理するためにautofacで決定論的処分のものを使用していて、よく私は一種のそれを好みます。
もう1つは、基本的にはASPNet環境のみをターゲットにしており、取引がWebリクエストに結びついているという意識的な決定を下したことです。したがって、Web要求パターンごとのトランザクション。
私はのIHttpModuleで処理コードこのエラーを行うことができるのので:
void context_Error(object sender, System.EventArgs e)
{
_containerProvider.RequestContainer.Resolve<IUnitOfWork>().Rollback();
}
私はあまりにも密接にNHibernate.Burrowを見て撮影していないが、私はほとんどありませんが、何かがあると確信していますこれの。
出典
2009-11-04 15:25:50
Min
私は解決策が好きです。しかし、別の問題は、どのような方法で[トランザクション]を適用すべきかということですか?このhttp://nhprof.com/Learn/Alert?name=DoNotUseImplicitTransactionsによると、セッションがある場合は常にトランザクションが必要なようですが、このソリューションでは、セッションが使用されているどこでも[トランザクション]を手動で追加する必要があります。 –
変更されたバージョンを確認してください。あなたはおそらくそこからそれを変更する方法を知っているでしょう。 また、[Transaction]属性をスキップして、常にトランザクションを開始することもできます。それはあなたの選択です。時々私は別のトランザクションで2つのことをする必要があったので、私は属性が必要でした。 私はこのようにしました: //トランザクション属性なし public virtual void CallThis() { Trans1(); //コミット Trans2(); //コミット } [トランザクション] パブリック仮想空TRANS1(){} [トランザクション] パブリック仮想空TRANS2(){} – dmonlord
次の2つのトランザクションのためのユースケースを説明してもらえますか?これは重要なことです。なぜなら、同様のユースケースに遭遇する可能性がある場合は、問題を別の方法で見ていきます。 –