分享
 
 
 

不为"事务"而"事务"

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

本问首发于:不为"事务"而"事务"

背景:

最近在做一个项目,需要用到两个第三方组件:北京莲塘语音组件和CMailSever

前者作为语音聊天室的二次开发组件,后者用于网站的小型邮件系统二次开发组件

需求:

用户在主程序登陆后,无须再次登陆聊天室和邮件系统,即实现一次登陆,全站通行

下面将给出对应方案以及其对事务处理的依赖程度,并给出解决方案

方案:

用户在注册时,同时向聊天室和邮件系统注册一个用户,在用户修改密码时对应修改

聊天室和邮件系统,这样当用户进入聊天室和邮件系统,主系统只需要向其传递用户和密码

即可满足需求

该方案存在的问题及其解决方案:

在用户注册或者修改密码信息时,如果有一个聊天室和邮件系统出现错误,那么用户

将有可能不能登陆其中一个系统,这就提出一个原子事务的问题,为注册和修改密码加上

原子事务处理,C#伪代码如下:

using System.EnterpriseServices ;

[Transaction(TransactionOption.Required)]

public class Users : System.EnterpriseServices.ServicedComponent

{

[AutoComplete]

public static void ModifyPassword(string userName , string olePassword , string newPassword)

{

ModifyMainSystemPassword(userName,newPassword) ; //修改主程序数据库密码

ModifyVoiceChatPassword(userName,newPassword) ; //修改聊天室密码

ModifyMailSystemPassword(userName,newPassword) ; //修改邮件系统密码

}

}

这样就可以实现当有一个系统修改密码出错时都会自动回滚到原来的状态了,OK,问题解决了!

进一步思考:

但事情却没有想象的简单,使用以上代码必须存在一个前提条件:聊天室和邮件系统组件必须支持事务性,

这样才能在应用程序之间共享事务,达到事务提交/回滚的目的

思路暂时中断.......

在CSDN论坛得到思归的帮助:如何对非事务性组件实现事务处理即使用所谓的资源补偿器(CRMs),下面简要说说实现的步骤

对于第1,2,4步可以在SDK中搜索System.EnterpriseServices.CompensatingResourceManager命名空间得到更

详细的信息,或则参见Compensating Resource Managers (CRMs)

这里贴出代码是为了实现的完整性,第3步是我本人扩充的,SDK无此描述

1,实现一个CRM类

using namespace#region using namespace

using System;

using System.IO;

using System.Reflection;

using System.EnterpriseServices;

using System.EnterpriseServices.CompensatingResourceManager;

[assembly: ApplicationActivation(ActivationOption.Server)]

[assembly: ApplicationCrmEnabled]

[assembly: AssemblyKeyFile("crm.key")]

#endregion

namespace CrmServer

{

实现代码#region 实现代码

[Transaction]

// Create a Worker class.

public class CRMWorker:ServicedComponent

{

public void CRMMethod(string fileName, bool bCommit)

{

// Create clerk object.

Clerk clerk = new Clerk(typeof(CRMCompensator), "CRMCompensator", CompensatorOptions.AllPhases);

clerk.WriteLogRecord(fileName);

clerk.ForceLog();

if (bCommit)

ContextUtil.SetComplete();

else

ContextUtil.SetAbort();

}

}

// Create class derived from Compensator class.

public class CRMCompensator:Compensator

{

bool bBeginPrepareCalled = false;

bool bPrepareRecordCalled = false;

bool bBeginCommitCalled = false;

bool bCommitRecordCalled = false;

bool bBeginAbortCalled = false;

bool bAbortRecordCalled = false;

String _fileName;

public override void BeginPrepare()

{

bBeginPrepareCalled = true;

}

public override bool PrepareRecord(LogRecord rec)

{

Object o = rec.Record;

_fileName = o.ToString();

bPrepareRecordCalled = true;

return false;

}

public override bool EndPrepare()

{

if (!bBeginPrepareCalled)

{return false;}

if (!bPrepareRecordCalled)

{return false;}

if (_fileName==null)

{return false;}

// This is a Prepare Phase success.

return true;

}

public override void BeginCommit(bool fRecovery)

{

bBeginCommitCalled = true;

}

public override bool CommitRecord(LogRecord rec)

{

bCommitRecordCalled = true;

return true;

}

public override void EndCommit()

{

if (!bBeginCommitCalled)

{return;}

if (!bCommitRecordCalled)

{return;}

if (_fileName==null)

{return;}

// This is a Commit Phase success.

}

public override void BeginAbort(bool fRecovery)

{

bBeginAbortCalled = true;

}

public override bool AbortRecord(LogRecord rec)

{

bAbortRecordCalled = true;

Object o = rec.Record;

_fileName = o.ToString();

return true;

}

public override void EndAbort()

{

if (!bBeginAbortCalled)

{return;}

if (!bAbortRecordCalled)

{return;}

if (_fileName==null)

{return;}

// This is an Abort Phase success.

}

}

#endregion

}

2,生成强名,编译成托管dll

[C#]

sn –k crm.key

csc /t:library /r:System.EnterpriseServices.dll crm.cs

3,使用命令行把托管dll注册为com+服务

RegSvcs /:appname : CrmServer CrmServer.dll

4,在应用程序中调用com+服务

[示例代码]

using namespace#region using namespace

using System;

using System.IO;

using System.EnterpriseServices;

using CrmServer;

using System.Runtime.InteropServices;

#endregion

class CRM

{

public static int Main()

{

string logfilename = "crm.log";

Console.WriteLine("Creating a managed CRM worker object
");

CRMWorker crmworker = new CRMWorker();

Console.WriteLine("Demonstrating a worker commit
");

crmworker.CRMMethod(logfilename, true);

Console.WriteLine("Demonstrating a worker abort
");

crmworker.CRMMethod(logfilename, false);

Console.WriteLine("DONE!");

return 0;

}

}

哇哈!终于可以交一份满意的差了!

准备在项目上实现上面的方案了,但是快乐之后仍需理智的思考,这样真的可以实现我们的要求吗?

这个方案至少有以下问题:

1,需要在服务器注册com+服务,部署不方便;

2,代码结构变复杂了

3,如果我们的web应用程序需要通过mono部署在linux系统呢?

......

晕到!别挑刺儿了......

不满是前进的唯一动力,会有更好的解决方案吗?我不断问我自己

终于工夫不负有心人,终于想到一个“完美的方案”:

1,分解模块,把聊天室和邮件系统和主系统独立出来

2,在用户注册时,所有用户的聊天室和邮件系统密码都是一样的,这个密码信息存储在配置文件或数据库中

这样当用户进入聊天室和邮件系统传递这个密码过去就OK了

3,用户修改密码时,不需要修改聊天室和邮件系统密码,因为它们永远是一样的

这样做的话,就剩下一个问题,如果注册的时候出错怎么办?下面给出两种解决方案:

1,在用户每次登陆前,都重新注册一次[不怎么好]

2,当用户注册时忽略错误,在后台提供一个给管理员手工添加用户信息到聊天室和邮件系统的功能,当用户

出现问题时联系管理员处理[比较好]

众里寻他千百度,蓦然回首,那人却在灯火阑珊处

自得其乐,板砖不断......

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有