事务何时开始又何时结束
了解事务的开始和结束的过程可以使我们从一个事务边界里考察每个参与对象的行为和事务的边界情况。
COM+何时开始一个事务?在下面两种情况下COM+将自动开始一个事务:
1. 当一个非事务属性的Client调用了一个标识有需要或需要新事务的COM+组件
2. 当一个有事务属性的Client调用了一个标识有需要新事务的COM+组件
当COM+确定一个对象需要一个新的事务,那么它会首先在当前对象的位置开始一个事务,接着它在下面一些步骤进行一些操作:
1. COM+创建一个环境(Context)对象,设置其JIT activation和synchronization属性为需要,并且设置内部维护的consistent和done 标志位。
2. COM+通知DTC将开始一个事务,DTC配置一个物理的事务
3. DTC产生一个新的事务并将标识这个事务的GUID标识返回给COM+,事务标识将建立一个事务环境边界,所有参与事务的对象将分享这个标识。COM+将这个事务的引用保存到Context中
4. 当Client建立这个对象时,COM+在这个事务边界的环境中激活它
事务边界中的第一个对象是很特别的,它就是我们一般所说的根对象,一个事务中只能有一个根对象,根对象之下的其它对象被称为内部对象。
COM+何时结束一个事务?在下面三种情况下COM+将结束一个事务其结果是提交或回滚事务。
1. 事务的执行超过了期限,那么COM+将自动结束在超时期间没有提交的事务,和事务相关的所有对象不再处于激活状态(deactivating),事务回滚。一般缺省的事务超时时间是60秒。
2. 根对象在一个调用中完成它的工作,COM+释放它的引用(代理和存根还在),之后根对象不再处于激活状态,整个事务开始尝试提交。
3. 根对象被Client释放,COM+释放对象的引用(代理先没有了存根也没有了),之后根对象不再处于激活状态,整个事务开始尝试提交。
COM+提交或放弃事务
为了有效的工作,COM+在每个环境(Context)中维护着两个标志位consistent和done。这两个标志
位影响事务是提交还是放弃,开发人员靠改变这两个标志位来告诉COM+自己对事务的观点,COM+根据
这两个标志位的状态在通知DTC该如何和RM进行交互。事实上有一个真相一直被我们忽略:
具有事务属性的对象没有参与著名的两段提交过程(也就是说没有见证到整个事务的结果),只是所
有应征RM和DTC完成了这个过程(评票和实施,并且宣布结果)。整个事务边界中的所有对象仅是对事务
是否提交进行了投票,当所有的组件同意后,COM+将统计这些投票并把最终的一个结果告诉DTC,你曾
经为我创建的某个事务(由GUID标识的)可以提交了,DTC请求所有应征的RM也提交各自的改变。而此
时曾经参与投票的所有对象已经销毁或是去了对象池,总之它们已经不再处于激活状态了。也就是说根对
象在调用SetComplete之后简单的获得了一个简单的S_OK返回(事务何时开始和结束它根本不知道),其
他对象对事务结果更是一无所知(只是在临死前投下自己的一票),两段提交过程可能失败。那么COM+
会更改原来根对象获得的S_OK的返回值(CONTEXT_E_ABORTED),最后只有根对象的Client知道事务
最终的结果。当然根事务如果调用SetAbort,那么结果是预先可以知道的,但根事务象上面说的一样,仍
然不是处于激活状态。简单的说,根对象通过请求被释放来强迫COM+进入它的事务表决。根对象释放之
后,COM+也会释放事务域里的所有对象,因此这之前所有对象的暂时表决必须在COM+统计投票之前确
定下来(这是最后期限),之后COM+知道是提交还是回滚事务,事务被强迫隔离起来不再允许任何线程
或对象进入(隔离是JIT激活要求的,如果不隔离对象还可以再进来或是对象可能带着状态参与到下一次的
其它事务中,而这种隔离保证是靠同步域(另外一个)来做到的,所以整个事务一直到最后都是安全
的)。
开发人员如何控制这两个标志位呢,特别是如果自己实现事务机制时,我们必须清楚这个投票算法。
下面的表列举我们使用的方法来修改这两个标志位:
可以使用的方法或函数
|
Consistent Bit
|
Done Bit
|
IObjectControl::SetComplete
|
True
|
True
|
IObjectControl::SetAbort
|
False
|
True
|
IObjectControl::EnableCommit (default)
|
True
|
False
|
IObjectControl::DisableCommit
|
False
|
False
|
IContextState::Get/SetMyTransactionVote
|
|
根据传入参数
|
IContextState::Get/StateDeactivateOnReturn
|
根据传入参数
|
|
COM+根据下面的规则使用这两个标志位来收集投票:
1. 缺省的情况下,COM+新建立一个环境(Context)时,consistent设置为true,done位被设置成false,也就是表中列的EnableCommit的情况
2. COM+将在当前函数返回时检查,如果done 位是true,那么COM+将使这个对象失去激活(deactivate),否则是false,COM+则继续保留这个对象。
3. COM+只有在方法调用返回或是当一个对象失去激活状态时检查done位的值,如果为true,那么COM+才注意consistent 位的值,如果consistent位是true,那么表明它赞成提交,否则表明要回滚。
4. 只有在对象失去激活时,COM+才读取事务表决。如果对象不向COM+请求释放,那么就在最后Client释放它之后,读取表决。即只有当done位为true时,COM+才开始读取cnsistent标志位。
5. 由于整个事务边界中的所有对象将共享这两个标志位,所以每个标志位都在对象失去激活前都可以设置多次和进行多次改变(上面说的“对象的暂时表决”),COM+只取最后一次改变作为计数。
根据上面的规则,我们就可以在程序中进行这样的仿真以实现自己的事务机制:
缺省(class构造)
|
提交前
|
回滚前
|
暂时不提交
|
提交暂时不提交的
|
IsHappy = true
IsDone = false
|
IsDone = true
|
IsHappy=false
IsDone = true
|
IsDone = false
|
IsDone = true
|
IsHappy 表示consistent标志位,IsDone表示done标志位,然后我们的类里可以这样判断:
if(CurrentTranscationContext.IsDone)
{
if(CurrentTranscationContext.IsHappy)
{ //done== true && consistent== true
CurrentTranscationContext.Commit();
}
else
{ // done == true && consistent == false
CurrentTranscationContext.Rollback();
}
CurrentTranscationContext = null;
}
|