Understanding COM+ with VFP, Part 3
This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
Understanding COM+ with VFP, Part 3
Craig Berntson
Transactions are an important part of any data update mechanism. Part 3 of
this series by Craig Berntson introduces the Distributed Transaction Coordinator
and explains how to use transactions under COM+.
Transactions, transactions, transactions. Without them, we can't be sure that
data is getting written to all of the Tables involved in an update. Before
digging into how transactions work in COM+, let's do a quick review of
transactions.
A review of transactions
Joe wants to transfer $100 from his savings account to his checking
account. He walks up to the ATM, inserts his card, and presses the buttons to
initiate the transfer. Behind the scenes, this transfer can be accomplished two
ways. The first way is that the balance of Joe's savings account can be reduced
by $100 and then his checking account balance increased by $100. The
second option is that his checking account balance can be increased and then
his savings account balance decreased. But what happens if there's a system
crash between the two updates? Under the first scenario, Joe isn't happy. He's
lost $100. Under the second example, Joe is very happy. He's $100 richer, but
the bank has now lost $100. What we want is that, in the event of the
aforementioned crash, either both accounts must be updated or neither of the
accounts updated. To ensure that this happens is the purpose of transactions.
Transactions should follow the ACID rule—that is Atomicity, Consistency,
Isolation, and Durability. Atomicity means that either all or none of the update
is committed. Consistency means that if the transaction fails, the data is
returned to the same state as before the transaction started. Isolation means
that one transaction doesn't know what another transaction is doing. Finally,
Durability means that the transaction state is kept, no matter what happens to
the system. This is generally handled through the use of a transaction log.
We can implement transactions on our VFP data by using the BEGIN
TRANSACTION/END TRANSACTION/ROLLBACK commands. This pseudo-code shows the
preceding example:
BEGIN TRANSACTION
llSavingsOk = UpdateSavings(-100)
llCheckingOk = UpdateChecking(100)
IF llSavings AND llChecking
END TRANSACTION
ELSE
ROLLBACK
ENDIF
The transactions in VFP only work with VFP data, and VFP transactions fail
the Durability rule of ACID. There's no transaction logging.
If we're using SQL Server, we need to use a different mechanism. We can use
ADO commands to tell SQL Server when to begin and end a transaction or we can
code it in a stored procedure. However, what happens if the savings account is
in SQL Server and the checking account data is in Oracle? SQL Server
transactions will only work on SQL Server, and Oracle transactions will only
work on Oracle. We need a single transaction that will work against both
databases. That's where the Distributed Transaction Coordinator (DTC) comes in.
Using the DTC
The DTC allows us to have transactions that cross databases. This
means that we can have data in both SQL Server and Oracle that will be updated
by the same transaction. Under MTS and VFP 6, Fox data couldn't participate in a
DTS transaction. (This changes under COM+ and VFP7. More on that later.) Back to
the DTC.
The DTS uses a two-phase commit. Basically, in phase one, DTS asks the
database if it can do an update. If all of the databases respond yes to this
question, then phase two begins, in which DTS tells the database to update the
data. If any of the databases respond with a no, then DTS tells all of the
databases to roll back the update.
Let's look at how transactions were handled under MTS:
DEFINE CLASS Math AS SESSION OLEPUBLIC
FUNCTION Multiple(tnNum1, tnNum2)
LOCAL lnResult, loMtx, loContext
* Create a reference to the MTS object
loMtx = CREATEOBJECT("MTXAS.APPSERVER.1")
* Create a reference to the context object
loContext = loMtx.GetObjectContext()
lnResult = tnNum1 * tnNum2
* Commit the transaction if there is one and
* tell MTS that we're done using the component
loContext.SetComplete()
* We can also abort the transaction and
* tell MTS that we're done with the component
* loContext.SetAbort()
RETURN lnResult
ENDFUNC
ENDDEFINE
Note that when we either commit or abort the transaction, MTS will also
release the component. This means that if the very next command in our
application needs the component, we have to do another CREATEOBJECT() on the
client. Let's see how this changes in COM+:
DEFINE CLASS Math AS SESSION OLEPUBLIC
FUNCTION Multiply(tnNum1 AS Number, tnNum2 AS Number) ;
AS Number HELPSTRING "Multiplies ;
two numbers and returns the result"
LOCAL lnResult, loMtx, loContext, loContextState, ;
llDone, llGetDone, lnTxnState, lnGetTxnState
llDone = .T.
llGetDone = .F.
lnTxnState = 1
lnGetTxnState = 0
* Create a reference to the MTS object
loMtx = CREATEOBJECT("MTXAS.APPSERVER.1")
* Create a reference to the Context object
loContext = loMtx.GetObjectContext()
* Get an interface to the Context state
loContextState = GETINTERFACE(loContext, ;
"iContextState")
lnResult = tnNum1 * tnNum2
* Handle Transaction Setting (Consistency)
* 0 = commit, 1 = abort
loContextState.SetMyTransactionVote(lnTxnState)
loContextState.GetMyTransactionVote(@lnGetTxnState)
* Handle activation setting (Done)
* .T. = Deactivate, .F. = Leave activated
loContextState.SetDeactivateOnReturn(llDone)
loContextState.GetDeactivateOnReturn(@llGetDone)
RETURN lnResult
ENDFUNC
ENDDEFINE
In this example, we can either commit or abort the transaction with
SetMyTransactionVote, but still keep the instance of the component active until
we explicitly call SetDeactivateOnReturn with a .T. parameter.
You might now be wondering where the DTC fits in. COM+ automatically calls
the DTC for us. The DTC talks to the database through the use of a Resource
Manager. MTS and COM+ ship with Resource Managers for Oracle and SQL Server, but
not for VFP. That's why VFP data couldn't take part in MTS transactions.
It turns out that Resource Managers are very difficult to implement. So, COM+
has what are called Compensating Resource Managers (CRMs). CRMs are easier to
implement than a Resource Manager. By using a CRM we can have our Fox data be
involved in DTC transactions.
A CRM consists of two parts, the CRM Worker and the CRM Compensator. These
correspond to the two-phased commit of the DTC. A detailed discussion of the CRM
is beyond the scope of this article. However, VFP 7 ships with a CRM sample
application. You'll find it in the SAMPLES\COM+\CRM folder under your VFP 7
installation.
Configuring COM+ transactions
Like many of the features in COM+, transactions are managed at
runtime. Open the Component Services Manager applet and drill down to one of
your components. Right-click on the component and select Properties, and then
select the Transactions tab. You'll see five transaction settings (see
Figure 1 and Table 1).
Table 1. Transaction types supported for COM+
components.
|
Setting |
Description |
| Disabled | Transactions aren't needed. Set this when
you don't want the extra overhead of a transaction—for example, a
component that doesn't update any data. |
| Not Supported | Prevents a component from using a
transaction, regardless of the transactional state of the calling
component. |
| Supported | The component participates in the
transaction if one is active. |
| Required | The component participates in the
transaction if one is active. If there's no active transaction, a new one
is started. |
| Requires New | A new transaction is always started. |
You'll also notice the "Override global transaction timeout value"
check box. When you select Required or Requires New transactions, this check box
becomes enabled. You can then enter the number of seconds the transaction will
run before timing out.
That's it for transactions. In Part 4, we'll look at a COM+ feature that
gives you asynchronous calls: Queued Components.
To find out more about FoxTalk and Pinnacle Publishing, visit their website at
http://www.pinpub.com/html/main.isx?sub=57
Note: This is not a Microsoft Corporation website. Microsoft is not responsible for its content.
This article is reproduced from the July 2001 issue of FoxTalk. Copyright 2001, by Pinnacle Publishing, Inc., unless otherwise noted. All rights are reserved. FoxTalk is an independently produced publication of Pinnacle Publishing, Inc. No part of this article may be used or reproduced in any fashion (except in brief quotations used in critical articles and reviews) without prior consent of Pinnacle Publishing, Inc. To contact Pinnacle Publishing, Inc., please call 1-800-493-4867 x4209.
© Microsoft Corporation. All rights reserved.