2016-11-24 7 views
0

私はメッセージを待ち受けて状態をDBに更新するMQリスナーを持っています。 SpringでHibernateセッションを管理する設定があります。Hibernate更新を実行する際の不一致

以下は、MQリスナーの構成です。 MQメッセージを処理するためのJava側の

 <bean id="queue" class="com.ibm.mq.jms.MQQueue"> 
      <constructor-arg value="queuename" /> 
     </bean> 
     <bean id="listenerBean" class="com.mypackage.Listener"> 
       <property name="service" ref="myService" /> 
     </bean> 
     <bean id="listener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter"> 
       <constructor-arg><ref bean="listenerBean"/></constructor-arg> 
     </bean> 
     <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 
       <property name="connectionFactory" ref="connectionFactory" /> 
       <property name="destination" ref="queue" /> 
       <property name="messageListener" ref="listener" /> 
       <property name="exceptionListener" ref="exceptionListener" /> 
       <property name="sessionTransacted" value="true" /> 
       <property name="autoStartup" value="true" /> 
     </bean> 

public class Listener implements MessageDelegate{ 

     public MyService service; 

     @Override 
     public void handleMessage(Serializable message) { 
       service.process(message); 
     } 
} 

サービスクラスの処理方法は、DBを更新するために、DAOメソッドを呼び出します。

以下は、Spring sessionFactory bean org.springframework.orm.hibernate3.LocalSessionFactoryBeanに使用されるhibernateプロパティーです。

<property name="hibernateProperties"> 
      <props> 
        <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> 
        <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> 
        <prop key="hibernate.cache.use_second_level_cache">true</prop> 
        <prop key="hibernate.cache.use_query_cache">true</prop> 
        <prop key="hibernate.show_sql">false</prop> 
        <prop key="hibernate.generate_statistics">true</prop> 
        <prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache_db_custom.xml</prop> 
      </props> 
    </property> 

このSessionFactoryのは、私のDAO Beanに注入され、私はMQメッセージからとのために得る私は一意の値に基づいてBeanを取得するための基準にAPIを使用しています。このsessionを使用sessionFactory.getCurrentSession()

を使用して、私のセッションを取得します私が得たユニークな結果、私は成功に状態を変更し、私はsessionFactory.getCurrentSession()sessionに取得し、session.update()に電話してDBを更新してください。

hbmファイルを使用しているため、Beanに注釈はありません。これは、1対多または多対1のマッピングを持たない単純なBeanです。アノテーションは@Transactionalです。

以下は更新スニペットです。私はSpringがトランザクションを処理すると信じています。

Session session = sessionFactory.getCurrentSession(); 
    if(session != null && bean != null) { 
     session.update(bean); 
    } 

私はDBの更新が失敗したときにDBが正常に更新し、例外処理のために(私が追加、log4jの)ロガーを持っています。

ここには奇妙な部分があります。

ログがhibernateによってスローされた例外を表示しないマルチスレッド環境で、ログ表示DBが正常に更新されましたが、ステータスは更新されません。これはすべてのレコードではなく、一部のレコードでのみ発生します。正常に更新されたレコードがあります。私はデータの特定の問題を見つけることができません。

JUnitを使用して更新に失敗したレコードの1つを実行すると、正常に更新されました。

設定終了時に何かを見逃してしまったことを誰かに知らせてもらえますか?

+0

MQリスナーコードを追加して、リスナーの数を設定できますか? – developer

+0

@javaguy質問のMQリスナーコードを更新しました。 2つのサーバーに分散された8つのJVM上に8つのリスナーがあります。 – Prabhat

答えて

0

アプリケーションにデザイン上の問題があります。つまり、基本的には、マルチスレッドのJMSアプリケーションでは、コンシューマが複数のスレッドをリッスンしているときに、メッセージがプロデューサが生成した順序を失い、アプリケーションを慎重に設計しないと、データベース内の更新(何も例外なく、私たちは同じ問題に直面してしまいました)。

この問題を解決するには、データベース側から更新するレコードが本当に正しいかどうかをチェックするビジネスロジックを持つ必要があるということです(これを正しく処理するためには、ロック)。たとえば、アプリケーションがデータベーステーブル(増加順)にnumber_of_productsを保持している場合は、新しいメッセージがより高い価値の製品を提示した場合にのみ、新しい更新が行われることを確認する必要があります。

もう1つの解決策は、アダプター(シングルスレッドでなければならない)のようなエントリ層を作成し、いくつかのビジネスロジックを使用してシーケンス番号を生成することです(各product_typeのようにシーケンスがあります)更新。シーケンス番号が以前の値よりも小さい場合は、最新のものではないため、メッセージを無視する必要があります。つまり、最新のメッセージはすでにデータベースに更新されています。

+0

MQメッセージから受信した一意のIDは基本的にプロセスの一部です。このレコードは1日か2日前に「New」というステータスでDBに挿入されていたので、確かにDBに存在するはずです。対応するレコードが「完了」というステータスで更新されている限り、MQメッセージが消費される順序は気にしないでください。 – Prabhat

+0

新規と完了から離れた別のステータスは何ですか? – developer

+0

'進行中です 'がありますが、アプリケーション固有のものです。基本的に、 'New'に変更した後、何らかの処理が行われ、その後、' In Progress'に更新されてから、遅延があります。その後、アプリケーションはMQからメッセージを取得し、ステータスを「完了」に更新します。 MQからメッセージが受信されたにもかかわらず、「進行中」状態のレコードの一部が表示されます。 – Prabhat

関連する問題