Skip to main content

What you may need to know about DBTransaction::postChanges()

In some specific use case scenarios both entity objects and stored procedures may need to co exist in your business logic implementation. This may arise if you are migrating(replacing) existing applications with ADF based application, and your customer wants to reuse some pieces from the legacy application. When you start identifying reusable pieces, in most of the cases, all eyes may be on stored procedures - we may need to accept the realities ;). As the data update logic is scattered across entity objects and stored procedure you may end up in calling DBTransaction::postChanges() to post the entity changes to data base before invoking stored procedure. Usage of DBTransaction::postChanges() is permitted if you commit the transaction within the same request. However there are some points you may need to aware of to make your implementation more perfect.

 To understand the DBTransaction::postChanges(), let us take step back and analyze the transaction commit cycle first. Consider a typical use case , where you have modified entity data, and finally you call DBTransaction::commit () to commit the transaction.
The sequence of actions that happens behind the transaction commit cycle are as follows:
The DBTransactionImpl calls...

  1. applicationModule::beforeCommit() 
  2. validate for each entry in validation listener list ( this in turn validates each EO )
  3. applicationModule::afterCommit() 
  4. postChanges() on each entry in transaction post listener list 
  5. beforeCommit for each entry in transaction listener list 
  6. commit transaction 
  7. afterCommit() for each entry in transaction listener list - EO/VO cache is cleared based on the configurations.

DBTransactionImpl maintains 3 lists to carry out the commit cycle. 1. validation listener list 2. transaction post listener list 3.transaction listener list. When you dirty an EO instance, it will get added to these three lists. If you call DBTransaction::postChanges(), step 4 alone gets executed from the above sequence and this operation clears transaction post listener list alone. In nutshell EOs will remain attached to the validate/transaction listener list till you call commit. This may have some side effect in certain scenarios.
 In case if you need to invoke postChanges() multiple times, you can manually clear the above said lists as shown in the following code snippet
    // Get VewRowImpl someVewRowImpl from VO  
    someVewRowImpl.setAttribute( "SomeAttrib","New Value");  
    EntityImpl someEOImpl = someVewRowImpl.getEntity(0);  
    DBTransaction txn = getDBTransaction();  
    txn.validate();  
    txn.postChanges();  
    txn.removeTransactionPostListener(someEOImpl); 
 
    //The below two lines may cause your EO to skip 
    // beforeCommit() and afterCommit() call backs.
    //Normally you can skip the below two lines, 
    // use it if you need to clear the EO cache once data is posted to DB
    // This makes sense if you have millions of rows in an update and
    // and you want to get rid of the cached rows without any delay
    txn.removeTransactionListener(someEOImpl); 
    txn.clearEntityCache(null);   

Comments

subu said…
moerover i search over blog regards create operation in eoimpl. here is my problem
https://forums.oracle.com/forums/thread.jspa?threadID=2295513&tstart=0
sorry to disturb you here
Anonymous said…
What will be the impact of passivisation after we call postChanges(),due to time-out but the commit was not performed?

-Ramesh
Jobinesh said…
For a typical web application, you not supposed to call postChanges() if the current request cant commit the transaction.
Anonymous said…
Is it possible to check whether a transaction listener/listeners has already been attached to a transaction Object?

-Akila.
Jobinesh said…
Akila,
What is your use case?
Anonymous said…
My functionality is to populate data in train of pages and commit transaction at the end. In the beginning of my transaction i attach a listener to it. But when i cancel it and start it from first page, listener gets attached again. Handler gets fired twice for the same event(say before commit).


NOTE: The pages are designed by different app teams. So from my end, i should make sure that only a single listener is attached to transaction.

Please let me know if there is way to achieve this.

Thanks,
Akila.
Shrikant1988 said…
Requirement is like application should support 40 concurrent users simultaneously accessing same am pool instance at a time.



By modifying am pool configration we are able to acheive this in some module.



By whichever module in which we are using getDBTransaction().postChages().



It is behaving unconditionally.





To reproduce same scenarion on local machine we have off Enable AM pooling in AM configration.



In log we are seeing lot of passivation happening in backend server log.



We have dig down a lot in postChanges and its relation with passivation.



We concluded.

Postchanges temporarly post the data .But when AM imstance move back from passivation to activation it rollbacks (clear all temporary data)





So we need some alternative for postChages()
Jobinesh said…
You should not use postChanges() t if you are not committing transaction within the same request(for a web application). When Am gets 'recycled' framework will rollback the pending changes. So what you see is as expected.
Srini said…
Do deleted entities get added to the validationListener - did not make sense to me, but wanted to check?

Also is there some way to remove an entity once it has been added to validationListener. I see that there are method to remove from the other two listeners.
Jobinesh said…
>Do deleted entities get added to
>the validationListener
No
>to remove an entity once it
> has been added to
>validationListener.
It will be removed automatically after the validation cycle.The method
removeFromValidationListeners(..) is package private
Showstopper said…
Hi Jobinesh,

I've a scenario where I am calling a method test() which is present inside the postChanges() of an EOImpl.java class.

My requirement is that the method test() should be executed only once for a given transaction.

In cases where the postChanges() is called multiple times, the method test() also executes multiple times, and this causes issues.

I am looking for a solution that will execute the test() only once all all the postChanges() calls for that transaction.

One solution I tried was to use an hcmParam and set it to true if the method is executed once. and in the postChanges(), if the hcmParam valuse is true then i dont execute test().
This solution works fine, but in certain scenarios where there is no refresh in the page is involved, the test() is not invoked as the hcmParam is true, but in cases where the refresh in the page. the solution works fine

Kindly throw some light on this.

Thanks
Karthik

Popular posts from this blog

How to set Bind Variable Values at runtime ?

In this post I'm sharing a couple of approaches for programmatically setting bind variables values at run time. This post is an attempt to explain 'When to use what ?'[ In case if you are familiar with 'Bind Variables' in ADF BC, please refer Section 5.10, Working with Bind Variables in Fusion Developer's Guide ]

1. Set the Bind Variable value using RowSet::setNamedWhereClauseParam(...)

You can use use the setNamedWhereClauseParam(...) method on the ViewObject interface (which extends oracle.jbo.RowSet) to set the value for bind variables. Please note this sets the value on default RowSet. In other words, this doesn't have any effect on the secondary RowSets that you/system generates.
ViewObject vo = am.findViewObject("EmployeesView1"); vo.setNamedWhereClauseParam("bindVarDeptId", new Number(10)); vo.executeQuery();
2. Set the Bind Variable value using ViewObject's VariableValueManager::setVariableValue(...)

VariableValueManager Ma…