实践篇(3)--关于事务处理的一点细节

 很早就注意到了微软的MTS COM+,但是却很少使用,主要原因是因为它的第一次执行太慢,耗费的资源比较多。在服务器配置比较乐观的项目里,比如某移动公司和某知名跨国日化生产商的系统里,恰当地使用COM+反而使得整体负载和程序的框架变得很清晰。

    在castle中集成了NHibernateIntegration对NHibernate进行了集成,对Session和Transaction进行了很好的封装。但是在对发布的beta版进行了最基本的测试后,我发现这个开源的东西还比较简陋。于是通过SVN获取了最新的开发版本,发现已经完全重写了。所以我就一个经典的转账来看看他们各有怎样的表现.


测试场景:
  我们假设一个娱乐中心要通过银行把钱转给在本中心娱乐的那些玩家中的获奖者,娱乐中心的账号设在bank1;而获奖者的账号都在bank2.  以下是转账的规则:

1) 娱乐中心没有钱肯定不能转帐;
2) 一次转账额不能超过5000;
3) 银行账号不能有重复;

    在很多的经典例子中,都太简单,这里我们模拟在每次都转到新开账号上,如果对第二次转帐到同一玩家,您讲看到一个异常。我们看看这两个容器是否能经受考验!

以下就是针对COM+ 的程序片断:

using  System;
using  System.Data;

using  System.Reflection;

using  System.EnterpriseServices;
using  System.Runtime.InteropServices;
using  Dao;


[assembly: ApplicationName(
" COM+ demo " )]
[assembly: ApplicationActivation(ActivationOption.Library)]

namespace  Services  {
    [Transaction(TransactionOption.Required)] 
    [ObjectPooling(Enabled
=true,MinPoolSize=2,MaxPoolSize=4)]
    
public class MyService:ServicedComponent {
    

        
public MyService() {
            Console.WriteLine(Assembly.GetExecutingAssembly().FullName);
        }

        [AutoComplete]
        
public virtual void Transfer( string from_BankTag,string from_uid,
            
string to_BankTag ,string to_uid,
            
int money) {
            
if(money<0return ;

                
            Withdraw(from_BankTag,from_uid,money);
            CreateNewAccount(to_BankTag,to_uid,money);
        }


        


        
        [AutoComplete]
        
public virtual void Withdraw(string db, string uid,int money) {
            AccountDAO dao
=new AccountDAO(db);
            BankDataSet.AccountsRow acc
=dao.getAccount(uid);
            
if(acc==nullthrow new Exception("不存在!"+uid);
            
if(acc.Balance<money )    throw new Exception("余额不足!");
            
if (5000<money) throw new Exception("一次不能超过:"+5000);
            
            acc.Balance
-=money;
            dao.saveTable(acc.Table);
        }

        [AutoComplete]
        
public void InitDbs() {
            AccountDAO dao1
=new AccountDAO("demo1");
            AccountDAO dao2
=new AccountDAO("demo2");
            
            dao1.cleanTable();
            dao2.cleanTable();
            CreateNewAccount(
"demo1","alex",10000);
            CreateNewAccount(
"demo2","cx",0);
        }


        
public int getBalance(string db,string uid) {
            AccountDAO dao
=new AccountDAO(db);
            Dao.BankDataSet.AccountsRow acc
= dao.getAccount(uid);
            
if(acc==nullreturn 0;
            
return acc.Balance;
            
        }

        
private void CreateNewAccount(string db,string uid,int money) {
            AccountDAO dao
=new AccountDAO(db);
            
            BankDataSet.AccountsDataTable tbl
=dao.getScheme();

            BankDataSet.AccountsRow r
=tbl.NewAccountsRow();

            r.ID
=Guid.NewGuid().ToString();
            r.UserCode
=uid;
            r.Balance
=money;
            tbl.Rows.Add(r);

            dao.saveTable(tbl);
        }


    }

}


在MTS里运行COM+,您的相关组件必须使用强名称,请注意要把
[assembly: AssemblyVersion("1.0.0.0")] 明确设定,否则每次运行在组件管理其中都会产生新的版本。

我们再看看NHibernateIntegration的表现如何:

using  System;
using  System.Collections;

using  Demo.Entities;
using  Castle.Services.Transaction;
using  Castle.Facilities.NHibernateIntegration;

using  NHibernate;
using  NHibernate.Expression;

namespace  Demo  {

    [Transactional]
    
public class AccountDao:NHibernateGenericDao {
        
private readonly ISessionManager sessManager;

        
private readonly string dbTag;

        
public AccountDao(ISessionManager sessManager):base(sessManager) {
            
this.sessManager = sessManager;
            
this.dbTag=Constants.DefaultAlias;
        }

    
        
public AccountDao(ISessionManager sessManager,string DbTag):base(sessManager) {
            
this.sessManager = sessManager;
            
this.dbTag=DbTag;
        }


        [Transaction(TransactionMode.Requires)]
        
public virtual void Deposit( string uid,int money) {
        
            
using(ISession session = sessManager.OpenSession(dbTag)) {
                Account acc
=getAccount(session,uid);
                acc.Balance
+=money;
                session.Save(acc);
                
//session.Flush();
                
            }

            
        }


        
private int getMaxMoney() {
            
return 5000;
        }


        
public  Account getAccount(string uid) {
            
using(ISession session = sessManager.OpenSession(dbTag)) {
                IList list
=session.CreateCriteria(typeof(Account)).Add(
                
new NHibernate.Expression.EqExpression("UserId",uid)).List();
                
if(list!=null&&list.Count>0return list[0as Account;
                
return null;

            }

        }


        
private Account getAccount(ISession session,string uid) {
            IList list
=session.CreateCriteria(typeof(Account)).Add(
                
new NHibernate.Expression.EqExpression("UserId",uid)).List();

        
//    Account[] accs=this.FindAllWithCustomQuery("from Account where UserId='"+uid+"'") as Account[];
            if(list==null||list.Count<1return null;//throw new Exception("帐户不存在!");
            return list[0as Account;
            
        }

    
        
public virtual int getBalance( string uid) {
            
using(ISession session = sessManager.OpenSession(dbTag)) {
                Account acc
=getAccount(session,uid);
                
return acc.Balance;
            }

        }

        [Transaction(TransactionMode.Requires)]
        
public virtual void CrateNewAccount( string uid,int money) {
            
using(ISession session = sessManager.OpenSession(dbTag)) {
                Account acc
=new Account();
                acc.UserId
=uid;
                acc.Balance
=money;
                session.Save(acc);
                session.Flush();
                
//没有上面这句提交事务时发生问题,但也无法回滚了。
            }

        }


        [Transaction(TransactionMode.Requires)]
        
public virtual void Withdraw( string uid,int money) {
            
using(ISession session = sessManager.OpenSession(dbTag)) {
                Account acc
=getAccount(session,uid);
                
if(acc.Balance<money ) throw new Exception("余额不足!");
                
if (getMaxMoney()<money) throw new Exception("一次不能超过:"+getMaxMoney());
                
                acc.Balance
-=money;
                session.Save(acc);
                session.Flush();
                
            }

            
        }


        
    }

}


而上层的服务代码如下:
using  System;
using  System.Collections;

using  Demo.Entities;

using  NHibernate;
using  Castle.MicroKernel;
using  Castle.Services.Transaction;

namespace  Demo  {

    
/// <summary>
    
/// BlogDao 的摘要说明。
    
/// </summary>

    [Transactional]
    
public class BankService {
        
private  Castle.MicroKernel.IKernel _container; 

        
public BankService(IKernel k) {
            _container
=k;
                        
        }


        

        [Transaction(TransactionMode.Requires)]
        
public virtual void Transfer( string from_BankTag,string from_uid,
            
string to_BankTag ,string to_uid,
            
int money) {
            
if(money<0return ;

            AccountDao fromDao
=_container[from_BankTag] as AccountDao;
            AccountDao toDao
=_container[to_BankTag] as AccountDao;

            fromDao.Withdraw(from_uid,money);

            toDao.CrateNewAccount(to_uid,money);
//演示提交事务时发生问题

        
//    Account acc=toDao.getAccount(to_uid);
        
//    if(acc==null) toDao.CrateNewAccount(to_uid,0);
        
//    toDao.Deposit(to_uid,money);
            
        }


    
    }

}
castle配置文件如下:

<? xml version="1.0" encoding="utf-8"  ?>
< configuration >
    
< facilities >
        
< facility  id ="nhibernate" >
            
<!--  数据库一  -->
            
< factory  id ="demo1" >
                
< settings >
                    
< item  key ="hibernate.connection.provider" > NHibernate.Connection.DriverConnectionProvider </ item >
                    
< item  key ="hibernate.connection.driver_class" > NHibernate.Driver.SqlClientDriver </ item >
                    
< item  key ="hibernate.connection.connection_string" > Server=localhost;Database=demo1;Uid=sa;Pwd= </ item >
                    
< item  key ="hibernate.dialect" > NHibernate.Dialect.MsSql2000Dialect </ item >
                
</ settings >
                
< resources >
                    
< resource   name ="./Account.hbm.xml"   />
                
</ resources >
            
</ factory >
            
<!--  数据库二  -->
            
< factory  id ="demo2"  alias ="db2" >
                
< settings >
                    
< item  key ="hibernate.connection.provider" > NHibernate.Connection.DriverConnectionProvider </ item >
                    
< item  key ="hibernate.connection.driver_class" > NHibernate.Driver.SqlClientDriver </ item >
                    
< item  key ="hibernate.connection.connection_string" > Server=localhost;Database=demo2;Uid=sa;Pwd= </ item >
                    
< item  key ="hibernate.dialect" > NHibernate.Dialect.MsSql2000Dialect </ item >
                
</ settings >
                
< resources >
                   
< resource   name ="./Account.hbm.xml"   />
                
</ resources >
            
</ factory >
        
</ facility >
        
    
</ facilities >

    
< components >     
        
         
< component  id ="bank2"   >
          
< parameters >
                
< DbTag > db2 </ DbTag >
            
</ parameters >
         
</ component >
       
</ components >
</ configuration >


通过改造NHibernateIntegration,我们可以在输出窗口看到执行过程:
1) 启动Transfer事务;
2) 启动Withdraw事务;
3) 完成Withdraw处理;
4) 启动CrateNewAccount处理;
5) 完成CrateNewAccount处理;
6) 对bank1和bank2进行数据库事务提交;
7) 完成Transfer事务;

结论:
首次执行COM+明显慢一些;
COM+的逻辑没有发生混乱;而NHibernateIntegration在没有及时进行缓存刷新时发生了严重的逻辑错误并且不能回滚。


另外我在一些有递归的情况下进行测试发现:使用延迟加载会出现session closed 或者访问空值得异常情况。
让我们期待NHibernateIntegration的完善吧......

alex

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值