I am using spring MVC 3 and Hibernate 3.6, with Spring tx to manage the hibernate transactions,
Now I am doing an ajax request to a controller that when the controller returns a value I navigate to another page, and i keep checking the controller till the value is returned.
This controllers method invocation also have some database transactions to do, and what I am trying to do is to navigate when every thing is finished and the database tx is done and all is good, but what happens is that hibernate's persist() or save() method exits but the transaction is not started.
I debugged the code and found that spring does some kind of a queue to transactions until the request to the controllers is done, meaning it does not actuly do the transaction rather it says that the method save is done, and queue the transaction then do it later.
EDIT
This is my relevant code
$("#kse_search").click(function (e){
$.get('updateProgress',function(data){
if(data == 'NaN' || data < 0){
$(".modal-backdrop").removeClass("hidden");
$("#bar_carrier").removeClass("hidden");
$.get('kse.htm');
interval = setInterval("ajaxP()",1000);
}else{
alert("There is an ongoing query for the same session, please wait until its finished");
}
});
})
// updata progress
function ajaxP(){
$.get('updateProgress',function(data){
datain = data;
if(data != 404){
var bar = "<div id='please_wait' class='row-fluid'> </div> <div class='row-fluid'> <div class='span5 progress progress-striped active'> <div id='bar' class='bar'></div> </div> </div>";
if($("#bar").length == 0){
$("#bar_carrier").html(bar);
}
if(data < 100){
$("#bar").css("width",data+"%");
$("#please_wait").html("<font id='please-wait-font'>" +Math.round(data)+"% complete</font>");
}
else if(data >= 100 && (data == 203 || data == 204)){
var please_wait = "<font id='please-wait-font'>Finalizing and saving to database please wait<i class='icon-spinner icon-spin'</font>";
if($("#please-wait-font").length == 0)
{
$("#bar").css("width",data+"%");
}
else{
$("#please_wait").html(please_wait);
$("#bar").css("width",data+"%");
}
clearInterval(interval);
setTimeout('ajaxProgress()',2*60*1000);
}
}
else{
clearInterval(interval);
$("#bar_carrier").html("<h4 class='label label-success'>market is still open please try again later </h4>")
}
})
}
and this is my controller regarding the update progress and the initial request
@RequestMapping("/kse.htm")
public @ResponseBody String kseData(Model model){
parser.setExchange("kse");
boolean choice = parser.start();
return String.valueOf(choice);
}
@RequestMapping("/updateProgress")
public @ResponseBody String progress(Model model){
float progress = parser.getProgress();
if(progress != 404 && progress != 204 && progress != 203){
return String.valueOf((progress/parser.getTotalProgress())*100);
}
else{
return String.valueOf(progress);
}
}
this is my saving function in my dao, the function
public boolean add(T entity) {
getSession().save(entity);
return true;
}
this is my getSession() the factory is autowired
public Session getSession(){
return (this.factory.getCurrentSession()==null)?
this.factory.openSession(): this.factory.getCurrentSession();
}
and this is how my transaction is managed via xml config
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="tx" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="findById*" propagation="REQUIRED" />
<tx:method name="findBetween*" propagation="REQUIRED" />
<tx:method name="findFromTo*" propagation="REQUIRED" />
<tx:method name="updateOwnerId*" propagation="REQUIRED" />
<tx:method name="updateOwnerType*" propagation="REQUIRED" />
<tx:method name="findAllSearch*" propagation="REQUIRED" />
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="tx" pointcut="execution(* *..AbstractDao.*(..))" />
<aop:advisor advice-ref="tx" pointcut="execution(* *..TempDataDao.*(..))" />
<aop:advisor advice-ref="tx" pointcut="execution(* *..OwnershipDao.*(..))" />
<aop:advisor advice-ref="tx" pointcut="execution(* *..OwnersDao.*(..))" />
<aop:advisor advice-ref="tx" pointcut="execution(* *..ChangesDao.*(..))" />
<aop:advisor advice-ref="tx" pointcut="execution(* *..TargetCompaniesDao.*(..))" />
</aop:config>
The controller calls the method of the parser (a session scoped bean) to execute start the execution, the function of the parser is an Async one, which by its turn calls another method of a dao which does the saving, Every thing works fine and it the dao's method exits and then after all the request sent to update progress is done, the transactions start, are they Lazily done ? all I want to do is make the transation occur just as I reach the save method or any method infact.
EDIT 2
Ok this is my method that update the progress or the part of it that matters
if(found != null){
this.tempData = found;
notFound = dataChecker.checkData(found);
if(notFound.size() == 0){
saveAllData(addDuplicates(dataChecker.getModifiedHolders()));
this.progress = 204;
return true;
}
else
{
this.progress = 203;
return false;
}
}
return false;
Now I have noticed a little wierder behavior, the dataChecker is responsible for filling the notfound List,and while doing that it saves alot data to the database, now the progress should not be returned until all of that is done,
But what happens is that the progress is returned as 204 as if the datachecker has finished and the data was empty.
Then after that the transaction start to happen, Like datachecker only added them to a queue.
But this happens after I am navigate to the other page with an empty notFound, and when refresh the page after the transaction and every thing is done, the page now has the data.