721
Paradox 7.x. Set the database name to Delphi’s DBDEMOS directory
c:\program files\ common files\borland shared\data
. Save the connection string and reopen the TADOTable. You should see no difference from the previous example. Now run the application and click the
BeginTrans button. Success? Unfortunately, no. This is a cruel, cruel trick on the part of the Jet 4.0 OLE DB Provider. Make a few changes and click the RollbackTrans button; close the
application down and restart it. You will see that the changes that you made were permanent and your act of rolling them back made no difference at all. As I said, it is a cruel trick, because
transactions on a Paradox database cannot be rolled back, and this makes them rather useless. If you read through the section in this chapter on the Jet engine and, in particular, the section
on Paradox, you will recall that I mentioned that the support for Paradox is lower than most developers would like. Transaction processing is one such example.
Now let’s look at how Access handles transaction processing. Create an ODBC System Data Source Name using the ODBC Manager. Call it Northwind DSN, use the Microsoft
Access ODBC driver, and set the database to
Northwind.mdb
. In Delphi, change the TADO- Connection to use the ODBC OLE DB Provider and the new Northwind DSN. Now save
the connection string, change the
TADOTable
’s
TableName
from Customer to Customers, and open it. Run the application and click the BeginTrans button. At last, transaction processing
that works. You can make changes to the Northwind database and roll back the changes, and they will be rolled back However, something you cannot do is start a transaction within a
transaction. Try clicking the BeginTrans button twice and you get a “Cannot start more trans- actions on this session” error. This is a limitation of ODBC and not the Jet engine and is a
useful example of why you should always try to locate an OLE DB provider for your DBMS instead of an ODBC driver.
Nested Transactions
If you try the same test again but use the Jet 4.0 OLE DB Provider, you will see that you can click the BeginTrans button five times before receiving an error on the sixth attempt. Jet sup-
ports nested transactions, which are transactions that exist within the context of another trans- action. The nested or inner transaction can be committed or rolled back without affecting the
outcome of the outer transaction. Let’s work through a sequence of steps to be sure of how this works:
1. Begin a transaction.
2. Change the
ContactName
of the Around The Horn record from Thomas Hardy to Dick Solomon.
3. Begin a nested transaction.
Transaction Processing
Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com
722
4. Change the
ContactName
of the Bottom-Dollar Markets record from Elizabeth Lincoln to Sally Solomon.
5. Roll back the inner transaction.
6. Commit the outermost transaction.
The net effect is that only the change to the Around The Horn record is permanent. If, however, the inner transaction had been committed and the outer transaction rolled back,
then the net effect would be that none of the changes were permanent even the changes in the inner transaction. Although we are using Access to illustrate this behavior, the behavior
is the same for all OLE DB providers that support nested transactions. This, of course, leads us to an ongoing theme in our ADO exploration: The ADO documentation simply states
how any given feature is supposed to work when it is fully implemented by the OLE DB provider and the DBMS, but it does not necessarily follow that it is implemented for all OLE
DB providers and all DBMSs. In the example of nested transactions, we have seen that ODBC does not support them and that the Jet OLE DB Provider supports up to five levels of nested
transactions. The SQL Server OLE DB Provider supports nesting, but this depends on the version of SQL Server being used. In SQL Server 7.0 and 2000, full nested transaction support
is provided. In SQL Server 6.5, only “fake nesting” is supported, where all inner-transaction instructions are ignored. You can commit and roll back inner transactions without any effect.
It is only the outermost transaction that decides whether the complete sum of all of the work is committed or rolled back.
There is another issue that you should consider if you intend to use nested transactions. TADOConnection has a property called
Attributes
, which determines how the connection should behave when a transaction is committed or rolled back. It is a set of
TXActAttributes
that, by default, is empty. There are only two values in
TXActAttributes
: xaCommitRetaining and xaAbortRetaining this value is often mistakenly written as xaRollbackRetaining because
this would have been a more logical name for it. When xaCommitRetaining is included in
Attributes
and a transaction is committed, a new transaction is automatically started. When xaAbortRetaining is included in
Attributes
and a transaction is rolled back, a new transac- tion is automatically started. This means that if you include these values in
Attributes
, a transaction will always be in progress, because when you end one transaction another will
always be started. Most programmers prefer to be in greater control of their transactions than allowing them to be automatically started, so these values are not commonly used.
However, they have a special relevance to nested transactions. If you nest a transaction and
Chapter 16 • ActiveX Data Objects
Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com
723
set
Attributes
to
[xaCommitRetaining, xaAbortRetaining]
, then the outermost transaction can never be ended. Consider the sequence of events:
1. An outer transaction is started.