Subject | Re: [Firebird-Architect] Feature request... |
---|---|
Author | David Jencks |
Post date | 2004-05-28T02:45:05Z |
Your use case does not require or even use nested transactions. You
can easily get the effect you want by including a TransactionContext
object in each method signature.
TransactionContext {
Object initiator
boolean rollbackOnly
}
A transactional method receiving a null TransactionContext parameter
creates a TransactionContext object with initiator as itself, and
starts a transaction. It passes the TransactionContext to any
transactional method it may call. Any method that wishes to cause the
transaction to be rolled back sets rollbackOnly. Before a
transactional object exits, it looks at the TransactionContext to see
if it started the transaction: if so, it commits or rolls back as
indicated.
myTransactionMethod(TransactionContext txcx, Object[] stuff)
if (txcx == null) {
txcx = new TransactionContext(this);
}
try {
//do stuff
} catch (Exception e) {
txcx.rollbackOnly = true;
throw e;
} finally {
if (txcx.initiator == this) {
if (txcx.rollbackOnly) {
transaction.rollback();
} else {
transaction.commit();
}
}
Alternatively you can use a framework such as j2ee that handles
transactions declaratively for you.
david jencks
can easily get the effect you want by including a TransactionContext
object in each method signature.
TransactionContext {
Object initiator
boolean rollbackOnly
}
A transactional method receiving a null TransactionContext parameter
creates a TransactionContext object with initiator as itself, and
starts a transaction. It passes the TransactionContext to any
transactional method it may call. Any method that wishes to cause the
transaction to be rolled back sets rollbackOnly. Before a
transactional object exits, it looks at the TransactionContext to see
if it started the transaction: if so, it commits or rolls back as
indicated.
myTransactionMethod(TransactionContext txcx, Object[] stuff)
if (txcx == null) {
txcx = new TransactionContext(this);
}
try {
//do stuff
} catch (Exception e) {
txcx.rollbackOnly = true;
throw e;
} finally {
if (txcx.initiator == this) {
if (txcx.rollbackOnly) {
transaction.rollback();
} else {
transaction.commit();
}
}
Alternatively you can use a framework such as j2ee that handles
transactions declaratively for you.
david jencks
On Thursday, May 27, 2004, at 04:11 PM, Alexandre Benson Smith wrote:
> unordained wrote:
>
>> Ann, thanks for taking an interest.
>>
>> The semantics I would expect from nested transactions are as follows:
>>
>> (At the global database level)
>> - A transaction is truly committed if it has committed and all parent
>> transactions have committed.
>> - A transaction is truly rolled back if it has rolled back or any of
>> its parent transactions have
>> rolled back.
>>
>> (If parent transactions are still active, then sub-transactions may
>> have some of these properties,
>> but aren't finalized.)
>>
>>
> ...snip...
>
>> If I'm wrong about the linearity issue, then ... many many apologies?
>>
>> -Philip
>>
>>
> Hi,
>
> My English is very poor to write descriptive text, so try hard to
> understand what I meant to say :-)
>
> I don't usually post on this list, but I have sometimes wished nested
> transactions.
>
> Why ?
>
> All my systems use OOD/OOP, So I have a bunch o Business Objects, that
> maps to relational objects, and has methods for get/set values
> (select/insert/update/delete) on database tables, and some business
> process, like subtract from stock, etc.
>
> I have an object called boStockMovement, that add a record on
> StockMovement Table, subtract/add the amount movemented on table
> Products.PhysicalQty, and a lot more...
> the method will be something similar to this:
>
> begin
> Start Transaction
> try
> insert in Table Movement
> update table Product
> etc.
> commit
> except
> rollback
> end
> end
>
> Then I have another object boInvoice that maps to Invoice Table
>
> When a Sales Order become an Invoice, I should movement the Stock (to
> reduce the physical quantity)
>
> The Method to transform the Sales Order in a Invoice is like this:
>
> begin
> StartTransaction
> try
> insert Invoice from Sales Order
> insert Bill (the Customer must pay)
> Movement the Stock (using boStockMoviment)
> Update Sales Order item to reflect the products sent to the
> costumer
> Commit
> except
> Rollback
> end
> end
>
> The Method for StockMoviment could be used alone, or inside other
> methods, so this method will try to create a transaction inside a
> transaction, what is not allowed.
>
> The solution we made for this situation is:
> We have a StartTransaction, Commit, Rollback Methods on your boObject
> (the base class that all business objects are derived).
> The StartTransaction Method has a Stack of Transactions, the
> transaction
> is put on the stack and if the stack was empty then create a new
> transaction,
> The Commit Method commits the transaction, and remove that from stack,
> and if that is the last one on the stack, then perform a "real commit"
> The Rollback Method, removes all transactions from the stack, and
> performs a real rollback.
>
> The Commit are just made when the last "virtual transaction" performs a
> commit
> The Rollback, rollbacks all transactions, doesn't mater in what level
> the situation that needs a Rollback was
>
> an example:
> boInvoice.StartTransaction (performs a real start transaction)
> try
> boInvoice.Insert;
> boInvoice.AddBill;
> for each Invoice Item do
> boStockMoviment.Movement(boInvoiceItem.ProductID,
> boInvoiceItemQuantity)
> (this occurs insed boStockMoviment.Movement)
> boStockMoviment.StartTransaction (there was another
> transaction
> on the stack, so do nothing)
> try
> insert in Table Movement
> update table Product
> etc.
> boStockMoviment.Commit (there are another transaction on
> the
> stack, so just remove it from the stack)
> except
> rollback (if this occur, generated an exception that will
> be
> catch on the upper level, and remove the transaction from stack)
> end
> end
> except
> rollback (if some exception occurs, this will be the last
> transaction
> on the stack, so performs a real rollback)
> end
>
> So I just perform Commit/Rollback on the last transaction on the stack
> If some rollback on the sub-transactions occurs, an exception will be
> generated, and catched by the upper level, that will peform another
> rollback, and so on until it reachs the last transaction on the stack
> that will perform real rollback
>
> The commit on the last transaction commits everything, and a rollback
> on
> any level rollbacks everything.
>
> All are running on the same transaction context, so evething is visible
> accorss sub-transactions, no dead-lock... It's not possible to just
> rollback a portion, if something goes wrong, everything should be
> redone...
>
> It's a simple approach, but solves my problem...
>
> Hope I could explain how I done it...
>
> see you !
>
> --
>
> Alexandre Benson Smith
> Development
> THOR Software e Comercial Ltda.
> Santo Andre - Sao Paulo - Brazil
> www.thorsoftware.com.br
>
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>