3

私はhibernate3と春を使用しています。

Javaコード:

クラスCommunicationServiceImpl、メソッドsendAllMessages:

Collection<MessageToSend> messagesToSend = this.repositoriesLocator.getMessageToSendRepository().getMessagesToSend();


        Iterator<MessageToSend> iteratorMesToSe = messagesToSend.iterator();
        while (iteratorMesToSe.hasNext()) {
            MessageToSend mts = iteratorMesToSe.next();

            MessageSender sender = new SmsSender(mts, this.repositoriesLocator);
            sender.start(); //run thread                
        }

SmsSender:

public class SmsSender extends MessageSender {

public SmsSender(MessageToSend messageToSend, RepositoriesLocator repositoriesLocator) {
    super(messageToSend, repositoriesLocator);      
}

public void sendMessages() {            
    try {
        MessageToSendSms messageToSendSms = (MessageToSendSms) this.messageToSend;                                                      
        Iterator<CustomerByMessage> itCbmsgs = messageToSendSms.getCustomerByMessage().iterator();          
        while (itCbmsgs.hasNext()) {                
            CustomerByMessage cbm = (CustomerByMessage) itCbmsgs.next();        

            //sms sending                           
            String sResult = this.sendSMS(cb.getBody(), cbm.getCellPhone());
            cbm.setStatus(CustomerByMessageStatus.SENT_OK);
            cbm.setSendingDate(Calendar.getInstance().getTime());                               
        }

        messageToSendSms.setStatus(messageToSendStats.PROCESSED)
        this.log.info("saving messageToSend..."); 
        //this line dont work!
        this.repositoriesLocator.getMessageToSendRepository().update(messageToSendSms);         
        this.log.info("messageToSend saved!");                      
    } catch (Exception e) {         
        this.log.error("Error sms sender " + e.getMessage());
    }       
}

これは私のappContext.xmlの一部です:

<bean id="serviceCommunication"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager">
        <ref local="transactionManager" />
    </property>
    <property name="target">
        <ref local="communicationServiceImpl" />
    </property>             
    <property name="transactionAttributes">
        <props>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>

<bean id="communicationServiceImpl"
    class="com.ninatec.fnet3.services.communication.impl.CommunicationServiceImpl"
    parent="serviceParent">
</bean>

HibernateRepository
repositoriesLocator.getMessageToSendRepository()。updateコード:

public void update(MessageToSend messageToSend) {
    try {
        this.getSession().update(messageToSend);
    } catch (HibernateException e) {
        this.log.error(e.getMessage(), e);
        throw e;
    }
}

エンティティMessageToSendは更新されていません。

CommunicationServiceImpl.sendAllMessages()を呼び出すと、コレクションにすべてのmessagesToSendがあります。MessageToSendごとに、メッセージを送信するためのスレッドを作成します。スレッドsmsSenderは正常に機能しますが、データベースの永続性は機能しません。オブジェクトMessageToSendの変更は、私のデータベースでは更新されていません。

ランダムエラーは次のとおりです。

セッションは終了しました、

プロキシを初期化できませんでした-セッションがありません、

プロキシを初期化できませんでした-所有しているセッションが閉じられました、

コレクションを休止状態の2つのオープンセッションに関連付けようとする違法な試みと

ロールのコレクションを遅延初期化できませんでした:セッションがないか、セッションが閉じられていません


    • スレッドについて。xsmsに1つのスレッドを使用したい。すべてのSMS送信者は、SMSのグループを送信します。

私のアーキテクチャでオブジェクトをセッションから明示的に切り離す方法がわかりません。

4

1 に答える 1

1

スレッドと Hibernate セッションで非常に悪いことをしています。まず第一に、CommunicationServiceImpl.sendAllMessages()トランザクションです。これは、コレクションMessageToSendを繰り返し処理している間、エンティティが Hibernate セッションに接続されていることを意味しますmessagesToSend。それはいいです。

ただし、エンティティごとに、そのエンティティを処理する新しいスレッド*を開始します。MessageToSendそのスレッド内で、いくつかのサブクエリや更新を含め、で多くの計算を実行します。これは、危険な競合状態が現れる場所です。

まだメインwhile (iteratorMesToSe.hasNext())ループ内にいる間にスレッドが開始された場合 (まだsendAllMessages()メソッド内にある) MessageToSend、親スレッドで開始された元のセッションにアタッチされたままになります。ただし、親スレッドが反復を完了した (終了したsendAllMessages()) が、子MessageSenderがまだ実行中の場合、上記のような一時的なエラーが発生します。" session closed" は基本的に、子スレッドが処理を完了する前に親スレッドがセッションを閉じたことを意味します。

簡単に言えば、Hibernate セッションにバインドされたオブジェクトを現在のスレッドから逃がしてはいけません。代わりに、それらをセッションから明示的に切り離し (たとえば、セッションをクリアするか、トランザクションをさらに上に移動して、オブジェクトを反復処理するときにオブジェクトがセッションにアタッチされないようにする)、処理された行ごとに新しいトランザクションを開始します。

* - 送信したい SMS ごとに新しいスレッドを作成しているようです。これはあまりスケーラブルではありません。送信するメッセージの総数が数千に達すると、システムが機能しなくなります。代わりに、スレッド プール ( ExecutorService) を使用します。

于 2012-10-16T18:04:40.830 に答える