我有一个MQ侦听器,该侦听器会倾听消息并将状态更新为db。我有一个设置,在春季管理冬眠会话。
下面是MQ侦听器配置。
<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>
在Java结束上处理MQ消息,
public class Listener implements MessageDelegate{
public MyService service;
@Override
public void handleMessage(Serializable message) {
service.process(message);
}
}
服务类中的过程方法调用DAO方法以更新DB。
以下是用于春季会话bean org.springframework.orm.hibernate3.LocalSessionFactoryBean
的休眠属性。
<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,我使用sessionFactory.getCurrentSession()
使用此session
我使用标准API根据我从MQ消息获得的唯一值获得BEAN,并且为了获得我获得的唯一结果,我将状态更改为成功,我再次致电sessionFactory.getCurrentSession()
,以获取session
并致电session.update()
更新DB。
当我使用HBM文件时,BEAN上没有注释。这是一个简单的豆,没有一对多或多一对一的映射。没有@Transactional
注释。
下面是更新片段。我相信春天照顾交易。
Session session = sessionFactory.getCurrentSession();
if(session != null && bean != null) {
session.update(bean);
}
我有一个记录器(由我添加,log4j)用于DB成功更新和异常处理,每当DB更新失败时。
这是奇怪的部分。
我已经遇到了多线程环境中的方案,在多线程环境中,日志没有显示Hibernate和Logs Show show db成功更新的任何例外,但是,状态尚未更新。这仅是针对某些记录而不是全部记录发生的。有成功更新的记录。我找不到任何特定数据的问题。
当我执行未使用Junit更新的记录之一时,它成功更新。
有人可以让我知道我是否错过了配置结束的任何东西?
您的应用程序中存在一个设计问题,即基本上,在多线JMS应用程序中,当消费者使用多个线程侦听时,消息将失去订单(生产者使用的是该订单产生的),如果您不仔细设计应用程序,您会在数据库中发现错误的更新(没有任何例外,我们在应用程序中遇到了同样的问题)。
因此,要解决问题,一种方法是您需要从数据库端具有业务逻辑来检查要更新的记录是真正正确的(您需要在单个交易中使用正确的锁定来处理此记录)。例如,如果您的应用程序将number_of_products
保存在products
数据库表中(按顺序越来越多),则您需要检查新消息才能在新消息带来更高的产品值时才进行。
另一个解决方案是,创建一个像适配器(应该是单线线程)这样的入口层,并使用某些业务逻辑生成序列编号(例如,对于每个product_type
,都会有一个序列),并在数据库更新期间检查该序列编号。如果序列号较低,则应忽略该消息,因为它不是最新消息,即,最新消息已更新到数据库。