我正在使用spring MVC 3和Hibernate 3.6,使用Spring tx来管理hibernate事务,
现在我正在向控制器发出ajax请求,当控制器返回一个值时,我导航到另一个页面,并且我一直检查控制器,直到返回值。
这个控制器方法调用也有一些数据库事务要做,而我想要做的是在每个事情完成并且数据库tx完成并且一切都很好时导航,但是会发生什么是hibernate的持久性()或save()方法退出,但事务未启动。
我调试了代码并发现spring对事务执行某种队列,直到对控制器的请求完成为止,这意味着它不会执行事务,而是表示方法已完成,并对事务进行排队然后再做。
修改
这是我的相关代码
$("#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>")
}
})
}
这是关于更新进度和初始请求的我的控制器
@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);
}
}
这是我的dao中的保存功能,功能
public boolean add(T entity) {
getSession().save(entity);
return true;
}
这是我的getSession()工厂自动装配
public Session getSession(){
return (this.factory.getCurrentSession()==null)?
this.factory.openSession(): this.factory.getCurrentSession();
}
这就是我通过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>
控制器调用解析器的方法(一个会话范围的bean)来执行开始执行,解析器的函数是一个Async,它依次调用dao的另一个方法来执行保存,Everything工作正常,dao的方法退出,然后发送到更新进度的所有请求完成后,交易开始,他们是懒惰完成的吗?我想要做的就是在我到达save方法或任何方法时进行转换。
编辑2
好的,这是我的方法,更新重要的进度或部分
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;
现在我注意到了一些更糟糕的行为,dataChecker负责填充未发现的List,并且在这样做的同时它将很多数据保存到数据库中,现在不应该返回进度,直到完成所有这些,
但是会发生的进展是返回为204,好像datachecker已经完成且数据为空。
然后事务开始发生,就像datachecker只将它们添加到队列中一样。
但是在我使用空的notFound导航到另一个页面之后会发生这种情况,并且在事务完成后刷新页面并且每件事都完成后,页面现在都有数据。
答案 0 :(得分:2)
请注意,默认的Spring事务管理是特定于线程的。每个事务状态(及其数据库连接)都存储在 ThreadLocal 变量(TransactionSynchronizationManager
)中。
这意味着,如果你在一个请求中启动事务(比如说线程http-0
)然后你尝试通过不同线程的数据库查询来检查进度(比如http-1
),那你就不会成功。 第二个线程将拥有自己的事务,并且在第一个线程提交更改之前,它不会看到绑定到第一个线程的事务中的数据。
您实际需要的是定期存储和更新某个变量中第一个线程(http-0
)的进度,然后可以被其他线程读取。
更新1:为了更具体一点 - 您的parser.getProgress()
不得调用数据库以获取正确的进度信息。
更新2:刚刚注意到您的getSession()
方法。在您自己的上打开新会话是一个严重的错误。这应该由Spring的事务管理器完成。如果sessionFactory.currentSession()
返回null
,则应抛出异常。