执行Hibernate更新时出现不一致

时间:2016-11-24 07:22:52

标签: java spring hibernate session

我有一个MQ侦听器,它侦听消息并将状态更新为DB。我有一个设置,其中Hibernate会话由Spring管理。

以下是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);
        }
}

服务类中的process方法调用DAO方法来更新DB。

以下是用于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中,然后使用sessionFactory.getCurrentSession()

获取会话

使用这个session我使用Criteria API根据我从MQ消息中获得的唯一值来获取bean,并且对于我获得的唯一结果,我将状态更改为成功,然后再次调用{{{ 1}}获取sessionFactory.getCurrentSession()并调用session来更新数据库。

由于我使用的是hbm文件,因此bean上没有注释。它是一个简单的bean,没有一对多或多对一的映射。没有session.update()注释。

以下是更新代码段。我相信Spring负责交易。

@Transactional

我有一个记录器(由我添加,log4j),以便在数据库更新失败时成功更新数据库并进行异常处理。

这是一个奇怪的部分。

我遇到过多线程环境中的一个场景,其中日志没有显示hibernate抛出的任何异常,并且日志显示DB已成功更新,但状态未更新。这只发生在某些记录中,而不是全部记录。有些记录已成功更新。我无法找到任何数据特定问题。

当我执行其中一条使用JUnit无法更新的记录时,它已成功更新。

如果我在配置结束时遗漏了任何内容,有人可以告诉我吗?

1 个答案:

答案 0 :(得分:0)

在您的应用程序中存在设计问题,即,基本上,在多线程JMS应用程序中,当消费者正在使用多个线程进行侦听时,消息将会松开订单(生产者已经生成)并且您将发现不正确的更新如果您没有仔细设计应用程序,那么在数据库中(没有任何例外情况,我们在申请中的某个时间内会遇到同样的问题)。

所以要解决这个问题,一种方法是你需要从数据库端获得一个业务逻辑来检查要更新的记录是否真的是正确的(你需要在一个事务中处理这个并且具有正确的锁定)。例如,如果您的应用程序在number_of_products数据库表中保持products(按递增顺序),那么您需要检查是否应该在新消息出现时执行新更新更高的产品价值。

另一个解决方案是,创建一个像适配器这样的入口层(它应该是单线程的)并使用一些业务逻辑生成一个序列号(比如每个product_type会有一个序列)并检查该序列号在数据库更新期间。如果序列号低于前一个值,则应忽略该消息,因为它不是最新消息,即最新消息已更新到数据库。