2013-06-05 3 views
1

가 완료 될 때까지 시작 최대 절전 모드 트랜잭션을 관리 할 수 ​​TX하지 않는 경우 컨트롤러는 다른 페이지로 이동하는 값을 반환하고 값이 반환 될 때까지 컨트롤러를 계속 확인합니다.최대 절전 모드 거래는 이제 <p></p> 내가 컨트롤러에 아약스 요청을하고있는 중이 야, MVC의 요청이 봄에, 내가 3.6 스프링 MVC 3를 사용하여 최대 절전 모드입니다

이 컨트롤러 메소드 호출에는 데이터베이스 트랜잭션이 포함되어 있으며, 모든 작업이 완료되고 데이터베이스 tx가 완료되고 모두 정상적으로 작동 할 때 탐색하는 것이지만 최대 절전 모드는 지속됩니다) 또는 save() 메소드가 종료되었지만 트랜잭션이 시작되지 않았습니다.

코드를 디버깅하고 컨트롤러에 대한 요청이 완료 될 때까지 스프링이 일종의 대기열을 처리한다는 것을 알았습니다. 즉, 트랜잭션이 실제로 트랜잭션을 수행하지 않는다는 것을 의미합니다. 거래 후 나중에해라.

편집

이 내 관련 코드

  $("#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, 기능

이내하는 getSession() 공장이

public Session getSession(){ 
    return (this.factory.getCurrentSession()==null)? 
      this.factory.openSession(): this.factory.getCurrentSession(); 
} 

를 autowire가되며이 내 트랜잭션이 컨트롤러는 파서의 메소드를 호출

<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> 

의 XML 설정을 통해 관리하는 방법입니다 (세션 Scoped Bean) 실행을 시작하려면 파서의 기능이 비동기식이며, 이는 차례대로 저장을 수행하는 DAO의 다른 메소드를 호출합니다. 모든 것이 잘 작동하고 DAO 메소드가 종료되고 모든 요청이 완료된 후 업데이트 진행 상태가 완료되면 트랜잭션이 시작되고, 그들은 게으르게 끝났습니까? 내가 원하는 것은 save 메소드 또는 어떤 메소드가 실제로 도달 할 때 변환이 일어나는 것뿐입니다.

편집 2

확인이는 dataChecker는 충전을 담당하는 진행 중이거나 지금은 조금 wierder 동작을 발견했습니다

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; 

을 중요한 그것의 일부를 업데이트 내 방법입니다 notfound List를 사용하고, 데이터베이스에 많은 데이터를 저장하는 동안, 모든 작업이 완료 될 때까지 진행 상황을 반환하지 않아야합니다.

하지만 진행 상황이 다시 나타납니다 datachecker가 끝나고 데이터가 비어있는 것처럼 204로 바뀝니다.

그런 다음 트랜잭션이 발생하기 시작합니다. datachecker가 대기열에 추가 한 것과 같습니다.

하지만 빈 noFound가있는 다른 페이지로 이동 한 후 이런 일이 발생하고 트랜잭션 후 모든 페이지가 새로 고쳐지면 페이지에 데이터가 저장됩니다.

+2

질문을 Controller 및 Ajax 요청의 관련 코드로 업데이트하십시오. 가장 중요한 부분은 트랜잭션 경계가 보일 것입니다. – Carsten

답변

2

기본 스프링 트랜잭션 관리가 스레드 특정이라는 점에 유의하십시오. 각 트랜잭션 상태 (및 데이터베이스 연결)는 ThreadLocal 변수 (TransactionSynchronizationManager)에 저장됩니다.

즉, 하나의 요청 (트랜잭션 http-0)으로 트랜잭션을 시작한 다음 다른 스레드 (데이터베이스에서 http-1)로 만든 데이터베이스 쿼리를 통해 진행률을 확인하려고하면 성공하지 못합니다. 두 번째 스레드는 자체 트랜잭션을 가지며 첫 번째 스레드가 변경 사항을 커밋 할 때까지 첫 번째 스레드에 바인드 된 트랜잭션의 데이터를 볼 수 없습니다.

실제로 필요한 것은 첫 번째 스레드 (http-0)의 진행을 정기적으로 저장하고 일부 변수에 업데이트 한 다음 다른 스레드에서 읽을 수 있도록하는 것입니다.


UPDATE 1 :은 조금 더 구체적으로 - 당신의 parser.getProgress()올바른 진행 정보를 얻기 위해 데이터베이스 호출 할 수 없습니다. 업데이트 2


:은 그냥 getSession() 방법을 발견했습니다.에 새로운 세션을 여는 것은 실수로 입니다. 이것은 Spring의 트랜잭션 관리자가 수행해야한다. sessionFactory.currentSession()null을 반환하는 경우 예외를 throw해야합니다.

+0

잘 thats 문제가 아니라, 진도가 DAO 메서드 호출을 기반으로하고 DAO 메서드가 종료되면 트랜잭션을 호출해야하지만 종료하지 않고 진행률을 증가시키고 계속해서 모든 작업이 완료되면 트랜잭션이 시작됩니다. – engma

+0

요점은 당신이 DAO 방법을 사용해서는 안된다는 것입니다. 검색어가 다른 거래가 될 것입니다. 어쩌면 당신은 질문에'파서 '예제를 추가 할 수 있습니다 ... –

+0

그냥'getSession()'코드를 발견했습니다. 내 질문을 업데이트했습니다. Spring의 트랜잭션 관리자는 세션을 열고 닫아야 만한다. 그렇지 않으면 AOP 구성을 돌아 다니고 있습니다. –