1

私はSpring MVC 3とHibernate 3.6を使用しており、Spring txを使用して休止状態のトランザクションを管理しています。

今、コントローラーが値を返したときに別のページに移動する ajax 要求をコントローラーに実行しています。値が返されるまでコントローラーをチェックし続けます。

このコントローラーメソッドの呼び出しには、実行するデータベーストランザクションもいくつかあります。私がやろうとしているのは、すべてが終了し、データベース tx が完了してすべてが正常になったときにナビゲートすることですが、何が起こるかというと、休止状態の persist() または 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構成を介して管理される方法です

<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) を呼び出して実行を開始します。パーサーの関数は非同期関数であり、それによって、保存を行う dao の別のメソッドが呼び出されます。すべてが正常に動作し、ダオのメソッドが終了し、進行状況を更新するために送信されたすべてのリクエストが完了した後、トランザクションが開始されます。それらは遅延して行われますか? 私がしたいのは、save メソッドまたは任意のメソッド infact に到達したときにトランザクションを発生させることだけです。

編集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 は、notfound リストを埋める責任があり、それを実行している間、データベースに多くのデータを保存しますが、すべてが完了するまで進行状況が返されないようにする必要があります。

しかし、データチェッカーが終了し、データが空であるかのように、進行状況が 204 として返されます。

その後、トランザクションが発生し始め、データチェッカーのようにそれらをキューに追加しただけです。

しかし、これは、空の notFound を使用して他のページに移動した後に発生し、トランザクション後にページを更新してすべての作業が完了すると、ページにデータが含まれるようになります。

4

1 に答える 1

2

デフォルトの Spring トランザクション管理はスレッド固有であることに注意してください。各トランザクション ステータス (およびそのデータベース接続) は、ThreadLocal変数 ( TransactionSynchronizationManager) に格納されます。

つまり、あるリクエストでトランザクションを開始し (たとえば、 thread http-0)、別のスレッド (たとえば、 ) から作成されたデータベース クエリを介して進行状況を確認しようとすると、http-1成功しません。2 番目のスレッドには独自のトランザクションがあり、最初のスレッドが変更をコミットするまで、最初のスレッドにバインドされたトランザクションからのデータは表示されません。

実際に必要なのは、最初のスレッド ( http-0) の進行状況を定期的に保存して更新し、他のスレッドが読み取ることができるようにすることです。


更新 1:もう少し具体的に言うと、正しい進捗情報を取得するためにparser.getProgress() データベースを呼び出してはなりません。


更新 2:getSession()あなたの方法に気付きました。自分で新しいセッションを開くのは重大な間違いです。これは、Spring のトランザクション マネージャーによって実行される必要があります。return の場合は例外をスローする必要がありsessionFactory.currentSession()ますnull

于 2013-06-11T12:15:35.613 に答える