下面以删除产品及其报价做为例子来说明AOP应用中的事务处理, 因数据库访问使用NHibernate, 所以使用NH中的事务.
思路如下:
在TransactionInterceptor(事务拦截器)中启动事务, 然后执行实现方法, 如果异常就回滚事务.
事务拦截器
TransactionInterceptor中的Invoke方法代码如下:
public class TransactionInterceptor : IMethodInterceptor {
public object Invoke(IMethodInvocation invocation) {
ISession session = Sessions.OpenSession();
// 将会话存入到管理器中, 这是共享会话的关键!
SessionManager.SetSession( session );
ITransaction trans = null;
try {
trans = session.BeginTransaction();
object result = invocation.Proceed();
trans.Commit();
return result;
}
catch ( Exception e ) {
if ( trans != null ) trans.Rollback();
throw e;
}
finally {
session.Close();
}
}
} //class TransactionInterceptor
业务对象和控制对象
Product和Enquiry同一般的业务对象, 这里就不贴出代码了.
// 产品控制对象接口, 用于应用Aspect.
public interface IProductCO {
void Delete( int productId );
} //interface ProductCO
// 产品控制对象实现代码:
public class ProductCO : IProductCO {
public void Delete( int productId ) {
// 从会话管理器中取出当前会话.
ISession session = SessionManager.GetSession();
Product product = (Product)session.Load( typeof(Product), productId );
session.Delete( " from Enquiry e where e.Product.ProductId = " + productId );
session.Delete( product );
}
} //class ProductCO
会话工厂
public class Sessions {
private static ISessionFactory factory;
public static ISession OpenSession() {
if ( factory == null ) {
Configuration cfg = new Configuration();
cfg.AddXmlFile( "product.hbm.xml" );
cfg.AddXmlFile( "enquiry.hbm.xml" );
factory = cfg.BuildSessionFactory();
}
return factory.OpenSession();
}
}
注, 为简化起见,省去了多线程的处理代码.
会话管理器
会话管理器是实现在线程中共享会话的关键, 这里使用TLS(线程本地存储)来存储ISession.
public class SessionManager {
public static void SetSession( ISession session ) {
Thread.SetData( Thread.GetNamedDataSlot("session"), session );
}
public static ISession GetSession() {
object obj = Thread.GetData( Thread.GetNamedDataSlot("session") );
if ( obj == null )
throw new Exception( "no session object!" );
return (ISession)obj;
}
} //class SessionManager
关于TLS和NamedDataSlot(命名数据槽)请参考.net sdk
Aspect配置
<aspectsharp>
<advices>
<interceptors>
<interceptor name="Transaction"
type="Toworld.Study.TransactionInterceptor, Study.Sample"
/>
</interceptors>
</advices>
<aspects defaultNamespace="Toworld.Study">
<aspect typeName="ProductCO">
<pointcut method="Delete" interceptor="Transaction"/>
</aspect>
</aspects>
</aspectsharp>
在业务控制对象ProductCO的Delete方法上定义截入点, 由TransactionInterceptor进行载入处理.
主程序代码
static void Main(string[] args) {
IProductCO product = AspectSharpEngine.Wrap( new ProductCO() ) as IProductCO;
product.Delete( 1 );
}
以上方法已经成功运行.