|
maj 01. 2007
Running Win32 kbmMW application servers on Linux using WINE
User article
apr 03. 2007
Performance comparison of kbmMemTable Std/Pro and AnyDAC CDS
nov 15. 2006
The king has died...
Borland/CodeGear
jun 16. 2006
The story of 3rdparty announcements and reactions on them
General
maj 29. 2006
Solving the 'cannot find drf file' problem when compiling packages.
Delphi
feb 21. 2006
kbmMWCnnfig.inc explained
kbmMW
feb 14. 2006
ReportBuilder 10 enduser report design with kbmMW
kbmMW/RB10
feb 09. 2006
Tips to setup IIS/ISA to operate as proxy between kbmMW client and server.
kbmMW/IIS
feb 08. 2006
Some thoughts about Borlands decision to split out its IDE/Tools division
Borland
jan 08. 2006
Things to be aware about when moving from Datasnap to kbmMW
kbmMW related
jan 08. 2006
Long running client controlled (stateful) transactions and the query service.
kbmMW related
jan 08. 2006
Secure messaging tips.
kbmMW WIB related
jan 08. 2006
Updating time in MSAccess Database with ADO
kbmMW related
jan 08. 2006
Upgrade from kbmMW v1 to kbmMW v2
kbmMW related
jan 08. 2006
Cross database and macro support
kbmMW related
|
Long running client controlled (stateful) transactions and the query service.
kbmMW related
|
|
How to use stateful transactions (long running
transactions)?
Firstly... stateful transactions are considered a 'no
no' in large n-tier setups. The reason is that stateful transactions hold up
ressources both on the db server and on application servers, which is bad for
scalability and ressource reuse.
However there are small setups where
stateful transactions (or other type stateful operations) are
required.
This can be done using a stateful service.
One way is to
create a query service via the service wizard, put a checkmark in the Stateful,
ConstructService, DestroyService, InitializeState and FinalizeState checkboxes
(on 2 pages in the wizard).
The checkmark in the Stateful checkbox makes
the service a stateful service. I.e. a client can hold one or more instances of
these for as long as the client decides.
When the service has been
generated, there will be a couple of empty methods in the generated code, namely
the InitializeState etc. methods.
In the public section of the service
class declare a connection variable:
MyConnection:TkbmMWCustomConnection;
MyTransaction:TkbmMWTransaction;
In the ConstructService method write the
following:
MyTransaction:=TkbmMWTransaction.Create;
MyTransaction.StartTransaction;
In the DestroyService method write the
following:
MyTransaction.Free;
MyTransaction:=nil;
In the InitializeState method write the
following:
// Wait max 10 secs for
a connection from the conneciton pool. MyConnection:=centralmodule.theconnectionpool.GetBestConnection(true,-1,10000); if
MyConnection=nil then raise Exception.Create('Cant initialize state for stateful
query
service.'); MyTransaction.AddConnection(MyConnection);
This
should obtain a kbmMW database connection which you can use later on. The
connection is already locked for your use when you get it so no other
thread or service will be able to use it until you unlock it. The connection
is added to the kbmMW transaction and as we specified the transaction to already
being started, kbmMW will automatically ensure that a true database
transaction is started on the database connection.
centralmodule is the
datamodule/form containing your database connection pool. theconnectionpool is
the database connection pool itself.
In the FinalizeState method write
the following.
if MyConnection<>nil
then begin MyTransaction.DeleteConnection(MyConnection);
MyConnection.UnlockConnection; end; MyConnection:=nil;
This
ensures that the connection is taken out of our transaction when the client
releases the state of the service, and the connection is then released back to
the connection pool for reuse later on.
Next you need to write some code
for the event handler OnAuthenticateQuery:
procedure Tyourservice.kbmMWQueryServiceAuthenticateQuery(Sender:
TObject; Query: TkbmMWCustomPooledCursor; ClientIdent:
TkbmMWClientIdentity; var Permissions:
TkbmMWAccessPermissions); begin Query.Connection:=MyConnection; Permissions:=[mwapExecute]; end;
This
ensures that the query component or stored procedure component that the client
is about to use, will use a specific connection, namely the one that
participates in the transaction we have defined.
At any time you can
choose to either MyTransaction.RollbackTransaction or
MyTransaction.CommitTransaction. Remember though that you need to start the
transaction again later on before you do any new updates/queries if they should
be performed in your specific transaction.
On the client side, you will
need to get the value of ActiveClient.StateID after the _first_ call to the
statefull query service, and store that value in some variable in the
client. Set all client query components ActiveClient.StateID to the value you
have stored when you want to access that specific statefull query
service. You can read up on the statemanagement in the 'Custom services'
whitepaper for more information about it.
Before the client exists, make
sure to release all held statefull services. This can be done by
doing:
yourclientquery.Client.ReleaseStateID(thestateidyoustored);
You
could use any other TkbmMWSimpleClient/TkbmMWPooledSimpleClient etc. instance to
do that. However one will automatically be instantiated for you for each client
query component and thus you can reuse that without problems.
--
best regards Kim Madsen kbm@components4developers.com www.components4developers.com
The
best components for the best developers kbmMW - kbmMemTable - kbmWABD -
kbmX10
(Top)
|
|