Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 插入后立即读取数据库记录后返回空数据库记录_Java_Spring_Jms - Fatal编程技术网

Java 插入后立即读取数据库记录后返回空数据库记录

Java 插入后立即读取数据库记录后返回空数据库记录,java,spring,jms,Java,Spring,Jms,我在JPA Hibernate实现中使用SpringJMS,我发现插入和即时读取同一条记录时会出现间歇性问题 web应用程序流: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instan

我在JPA Hibernate实现中使用SpringJMS,我发现插入和即时读取同一条记录时会出现间歇性问题

web应用程序流:

<?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:util="http://www.springframework.org/schema/util"
                xmlns:context="http://www.springframework.org/schema/context"
                xmlns:aop="http://www.springframework.org/schema/aop"
                xmlns:tx="http://www.springframework.org/schema/tx"
                xmlns:hz="http://www.hazelcast.com/schema/spring"
                xsi:schemaLocation="
                http://www.hazelcast.com/schema/spring
                http://www.hazelcast.com/schema/spring/hazelcast-spring-2.5.xsd
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/util
                http://www.springframework.org/schema/util/spring-util-3.0.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.0.xsd
                http://www.springframework.org/schema/tx
                http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

                <!-- Generic -->
                <context:annotation-config />
                <context:component-scan base-package="myapp.api" />
                <aop:aspectj-autoproxy/>

                <!-- JPA -->
                <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

                <tx:annotation-driven />

                <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

                <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                    <property name="dataSource" ref="dataSource" />
                    <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
                    <property name="persistenceUnitName" value="MyApp" />
                    <property name="jpaProperties">
                        <props>
                            <prop key="hibernate.use_sql_comments">true</prop>
                            <prop key="hibernate.generate_statistics">true</prop>
                            <prop key="hibernate.archive.autodetection">class</prop>
                            <prop key="hibernate.cache.use_second_level_cache">true</prop>
                            <prop key="hibernate.cache.provider_class">com.hazelcast.hibernate.provider.HazelcastCacheProvider</prop>
                            <prop key="hibernate.cache.use_query_cache">true</prop>
                            <prop key="hibernate.cache.use_minimal_puts">true</prop>
                        </props>
                    </property>
                </bean>


               <hz:hazelcast id="instance">
                    <hz:config>
                         //rest of Hazelast config maps here
                    </hz:config>
                </hz:hazelcast>

                <hz:hibernate-region-factory id="regionFactory" instance-ref="instance"/>

                <!-- Define JPA Provider Adapter -->
                <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <property name="showSql" value="true" />
                    <property name="generateDdl" value="true" />
                    <property name="databasePlatform" value="org.hibernate.dialect.OracleDialect" />
                </bean>

                <bean id="dataSourceTarget" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
                    <property name="URL" value="jdbc:oracle:thin:@server:1525:name" />
                    <property name="user" value="test" />
                    <property name="password" value="123" />
                    <property name="connectionCachingEnabled" value="true" />
                    <property name="connectionCacheProperties">
                        <props merge="default">
                            <prop key="MinLimit">5</prop>
                            <prop key="MaxLimit">50</prop>
                        </props>
                    </property>
                </bean>

                <bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
                    <property name="targetDataSource" ref="dataSourceTarget"/>
                </bean>


                <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
                    <property name="entityManagerFactory" ref="entityManagerFactory"/>
                    <property name="dataSource" ref="dataSource"/>
                </bean>

                <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/>

                <bean id="genericDAO" class="myapp.api.dao.impl.GenericDAOImpl">
                    <constructor-arg>
                        <value>java.io.Serializable</value>
                    </constructor-arg>
                </bean>

                <bean id="springContextHolder" class="myapp.api.util.SpringContextHolder" factory-method="getInstance" />

        <bean id="executionInterceptor" class="myapp.api.listener.backoffice.ExecutionInterceptor" />

        <!-- JNDI-->
        <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"/>

        <!-- JMS -->
        <bean id="jmsQueueConnectionFactory"  class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiTemplate">
                <ref bean="jndiTemplate"/>
            </property>
            <property name="jndiName" value="${jms.jndi.qconnectionfactory}">

            </property>
        </bean>
        <bean id="myJMSConnectionFactory" class="com.api.model.vo.backoffice.OpenMqConnectionFactoryBean">
            <property name="imqAddressList" value="${jms.imq.url}" />
            <property name="imqDefaultUsername" value="${jms.imq.user}" />
            <property name="imqDefaultPassword" value="${jms.imq.password}" />
            <property name="imqHost" value="${jms.imq.host}" />
            <property name="imqPort" value="${jms.imq.port}" />
        </bean>

        <bean id="stuMessageListener" class="com.api.listener.backoffice.STUMessageListener" />
        <bean id="storeListener" class="com.api.listener.backoffice.StorableMessageListener"/>

        <bean id="executionInterceptor" class="com.api.listener.backoffice.ExecutionInterceptor" />

        <bean id="stuJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
            <property name="destinationName" value="STUInputQ"/>
            <property name="sessionTransacted" value="false"/>
            <property name="messageListener" ref="stuMessageListener" />
            <property name="concurrentConsumers" value="5" />
            <property name="maxConcurrentConsumers" value="100" />
            <property name="receiveTimeout" value="30000" />
            <property name="cacheLevelName" value="CACHE_NONE" />

        </bean>
        <bean id="storeJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
            <property name="destinationName" value="ArchiveQ"/>
            <property name="sessionTransacted" value="false"/>
            <property name="messageListener" ref="storeListener" />
            <property name="concurrentConsumers" value="5" />
            <property name="maxConcurrentConsumers" value="100" />
            <property name="receiveTimeout" value="30000" />
            <property name="cacheLevelName" value="CACHE_NONE" />

        </bean>

 </beans>
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="com" transaction-type="RESOURCE_LOCAL">
  </persistence-unit>
</persistence>
public class STUMessageListener implements javax.jms.MessageListener{
       @Autowired
       StoringService storingService;

       @Transactional
       public void onMessage(Message message) throws RuntimeException { 
           try {
                Object omsg = ((ObjectMessage) message).getObject();
                if (omsg instanceof StorableMessage) {
                     StorableMessage storableMessage = (StorableMessage) omsg;
                     //StorableMessage insert into Database
                     storingService.store(storableMessage); 

                   //jms logic here to send message to next queue (ArchiveQ)
           }
           catch (Throwable ex) {
                throw new RuntimeException(ex);
            }
   }

     @Service("storingService")
        public class StoringServiceImpl{

            @Autowired
            MessagesDAO messagesDAO;

            @Transactional
            public StorableMessage store(StorableMessage storableMessage) {
                messagesDAO.save(storableMessage);
            }

        }

    @Repository("messagesDAO")
    public class MessagesDAOImpl{
        private Class<T> type
        @PersistenceContext
        EntityManager entityManager;

        public void save(T object) {
           entityManager.persist(object);
        }

        public T findById(Serializable id) {
           return entityManager.find(type, id);
        }
    }
public class StorableMessageListener implements javax.jms.MessageListener {
    @Autowired
    MessageDAO messageDAO;

    @Transactional
    public void onMessage(Message message) throws RuntimeException {
          if (omsg instanceof StorableMessage) {
               //this is where null is returned for the Messages object 18% of the time
               //sleep thread by 1 second logic here helps eliminate the null Messages object
              //uses same MessageDAO as above 
              Messages msg = messageDAO.findById(storableMessage.getMessageKey());
          }
    }
-数据发布到我的web应用程序web服务,并发送到Glassfish OpenMQ队列(下面是StInputQ)。
-com.api.listener.backoffice.STUMessageListener读取stuiputq队列并插入我们的Oracle数据库,然后将一条消息(使用新的数据库主键)发送到另一个队列(下面的ArchiveQ)。
-com.api.listener.backoffice.StorableMessageListener读取ArchiveQ队列,并尝试使用com.api.listener.backoffice.STUMessageListener插入的数据库记录的主键读取数据库

问题:

<?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:util="http://www.springframework.org/schema/util"
                xmlns:context="http://www.springframework.org/schema/context"
                xmlns:aop="http://www.springframework.org/schema/aop"
                xmlns:tx="http://www.springframework.org/schema/tx"
                xmlns:hz="http://www.hazelcast.com/schema/spring"
                xsi:schemaLocation="
                http://www.hazelcast.com/schema/spring
                http://www.hazelcast.com/schema/spring/hazelcast-spring-2.5.xsd
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/util
                http://www.springframework.org/schema/util/spring-util-3.0.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.0.xsd
                http://www.springframework.org/schema/tx
                http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

                <!-- Generic -->
                <context:annotation-config />
                <context:component-scan base-package="myapp.api" />
                <aop:aspectj-autoproxy/>

                <!-- JPA -->
                <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

                <tx:annotation-driven />

                <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

                <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                    <property name="dataSource" ref="dataSource" />
                    <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
                    <property name="persistenceUnitName" value="MyApp" />
                    <property name="jpaProperties">
                        <props>
                            <prop key="hibernate.use_sql_comments">true</prop>
                            <prop key="hibernate.generate_statistics">true</prop>
                            <prop key="hibernate.archive.autodetection">class</prop>
                            <prop key="hibernate.cache.use_second_level_cache">true</prop>
                            <prop key="hibernate.cache.provider_class">com.hazelcast.hibernate.provider.HazelcastCacheProvider</prop>
                            <prop key="hibernate.cache.use_query_cache">true</prop>
                            <prop key="hibernate.cache.use_minimal_puts">true</prop>
                        </props>
                    </property>
                </bean>


               <hz:hazelcast id="instance">
                    <hz:config>
                         //rest of Hazelast config maps here
                    </hz:config>
                </hz:hazelcast>

                <hz:hibernate-region-factory id="regionFactory" instance-ref="instance"/>

                <!-- Define JPA Provider Adapter -->
                <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <property name="showSql" value="true" />
                    <property name="generateDdl" value="true" />
                    <property name="databasePlatform" value="org.hibernate.dialect.OracleDialect" />
                </bean>

                <bean id="dataSourceTarget" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
                    <property name="URL" value="jdbc:oracle:thin:@server:1525:name" />
                    <property name="user" value="test" />
                    <property name="password" value="123" />
                    <property name="connectionCachingEnabled" value="true" />
                    <property name="connectionCacheProperties">
                        <props merge="default">
                            <prop key="MinLimit">5</prop>
                            <prop key="MaxLimit">50</prop>
                        </props>
                    </property>
                </bean>

                <bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
                    <property name="targetDataSource" ref="dataSourceTarget"/>
                </bean>


                <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
                    <property name="entityManagerFactory" ref="entityManagerFactory"/>
                    <property name="dataSource" ref="dataSource"/>
                </bean>

                <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/>

                <bean id="genericDAO" class="myapp.api.dao.impl.GenericDAOImpl">
                    <constructor-arg>
                        <value>java.io.Serializable</value>
                    </constructor-arg>
                </bean>

                <bean id="springContextHolder" class="myapp.api.util.SpringContextHolder" factory-method="getInstance" />

        <bean id="executionInterceptor" class="myapp.api.listener.backoffice.ExecutionInterceptor" />

        <!-- JNDI-->
        <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"/>

        <!-- JMS -->
        <bean id="jmsQueueConnectionFactory"  class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiTemplate">
                <ref bean="jndiTemplate"/>
            </property>
            <property name="jndiName" value="${jms.jndi.qconnectionfactory}">

            </property>
        </bean>
        <bean id="myJMSConnectionFactory" class="com.api.model.vo.backoffice.OpenMqConnectionFactoryBean">
            <property name="imqAddressList" value="${jms.imq.url}" />
            <property name="imqDefaultUsername" value="${jms.imq.user}" />
            <property name="imqDefaultPassword" value="${jms.imq.password}" />
            <property name="imqHost" value="${jms.imq.host}" />
            <property name="imqPort" value="${jms.imq.port}" />
        </bean>

        <bean id="stuMessageListener" class="com.api.listener.backoffice.STUMessageListener" />
        <bean id="storeListener" class="com.api.listener.backoffice.StorableMessageListener"/>

        <bean id="executionInterceptor" class="com.api.listener.backoffice.ExecutionInterceptor" />

        <bean id="stuJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
            <property name="destinationName" value="STUInputQ"/>
            <property name="sessionTransacted" value="false"/>
            <property name="messageListener" ref="stuMessageListener" />
            <property name="concurrentConsumers" value="5" />
            <property name="maxConcurrentConsumers" value="100" />
            <property name="receiveTimeout" value="30000" />
            <property name="cacheLevelName" value="CACHE_NONE" />

        </bean>
        <bean id="storeJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
            <property name="destinationName" value="ArchiveQ"/>
            <property name="sessionTransacted" value="false"/>
            <property name="messageListener" ref="storeListener" />
            <property name="concurrentConsumers" value="5" />
            <property name="maxConcurrentConsumers" value="100" />
            <property name="receiveTimeout" value="30000" />
            <property name="cacheLevelName" value="CACHE_NONE" />

        </bean>

 </beans>
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="com" transaction-type="RESOURCE_LOCAL">
  </persistence-unit>
</persistence>
public class STUMessageListener implements javax.jms.MessageListener{
       @Autowired
       StoringService storingService;

       @Transactional
       public void onMessage(Message message) throws RuntimeException { 
           try {
                Object omsg = ((ObjectMessage) message).getObject();
                if (omsg instanceof StorableMessage) {
                     StorableMessage storableMessage = (StorableMessage) omsg;
                     //StorableMessage insert into Database
                     storingService.store(storableMessage); 

                   //jms logic here to send message to next queue (ArchiveQ)
           }
           catch (Throwable ex) {
                throw new RuntimeException(ex);
            }
   }

     @Service("storingService")
        public class StoringServiceImpl{

            @Autowired
            MessagesDAO messagesDAO;

            @Transactional
            public StorableMessage store(StorableMessage storableMessage) {
                messagesDAO.save(storableMessage);
            }

        }

    @Repository("messagesDAO")
    public class MessagesDAOImpl{
        private Class<T> type
        @PersistenceContext
        EntityManager entityManager;

        public void save(T object) {
           entityManager.persist(object);
        }

        public T findById(Serializable id) {
           return entityManager.find(type, id);
        }
    }
public class StorableMessageListener implements javax.jms.MessageListener {
    @Autowired
    MessageDAO messageDAO;

    @Transactional
    public void onMessage(Message message) throws RuntimeException {
          if (omsg instanceof StorableMessage) {
               //this is where null is returned for the Messages object 18% of the time
               //sleep thread by 1 second logic here helps eliminate the null Messages object
              //uses same MessageDAO as above 
              Messages msg = messageDAO.findById(storableMessage.getMessageKey());
          }
    }
有时(约18%)StorableMessageListener中的读取操作返回null,即使记录确实存在。在我看来,即使insert返回序列生成的主键,在读取发生之前insert-commit似乎还没有处理。我在插入数据的方法和读取数据的方法的末尾添加了一个unix时间戳,当问题发生时,unix时间戳是相同的,因此看起来好像在提交最终完成之前读取得到了消息

临时解决方案:

<?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:util="http://www.springframework.org/schema/util"
                xmlns:context="http://www.springframework.org/schema/context"
                xmlns:aop="http://www.springframework.org/schema/aop"
                xmlns:tx="http://www.springframework.org/schema/tx"
                xmlns:hz="http://www.hazelcast.com/schema/spring"
                xsi:schemaLocation="
                http://www.hazelcast.com/schema/spring
                http://www.hazelcast.com/schema/spring/hazelcast-spring-2.5.xsd
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/util
                http://www.springframework.org/schema/util/spring-util-3.0.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.0.xsd
                http://www.springframework.org/schema/tx
                http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

                <!-- Generic -->
                <context:annotation-config />
                <context:component-scan base-package="myapp.api" />
                <aop:aspectj-autoproxy/>

                <!-- JPA -->
                <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

                <tx:annotation-driven />

                <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

                <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                    <property name="dataSource" ref="dataSource" />
                    <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
                    <property name="persistenceUnitName" value="MyApp" />
                    <property name="jpaProperties">
                        <props>
                            <prop key="hibernate.use_sql_comments">true</prop>
                            <prop key="hibernate.generate_statistics">true</prop>
                            <prop key="hibernate.archive.autodetection">class</prop>
                            <prop key="hibernate.cache.use_second_level_cache">true</prop>
                            <prop key="hibernate.cache.provider_class">com.hazelcast.hibernate.provider.HazelcastCacheProvider</prop>
                            <prop key="hibernate.cache.use_query_cache">true</prop>
                            <prop key="hibernate.cache.use_minimal_puts">true</prop>
                        </props>
                    </property>
                </bean>


               <hz:hazelcast id="instance">
                    <hz:config>
                         //rest of Hazelast config maps here
                    </hz:config>
                </hz:hazelcast>

                <hz:hibernate-region-factory id="regionFactory" instance-ref="instance"/>

                <!-- Define JPA Provider Adapter -->
                <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <property name="showSql" value="true" />
                    <property name="generateDdl" value="true" />
                    <property name="databasePlatform" value="org.hibernate.dialect.OracleDialect" />
                </bean>

                <bean id="dataSourceTarget" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
                    <property name="URL" value="jdbc:oracle:thin:@server:1525:name" />
                    <property name="user" value="test" />
                    <property name="password" value="123" />
                    <property name="connectionCachingEnabled" value="true" />
                    <property name="connectionCacheProperties">
                        <props merge="default">
                            <prop key="MinLimit">5</prop>
                            <prop key="MaxLimit">50</prop>
                        </props>
                    </property>
                </bean>

                <bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
                    <property name="targetDataSource" ref="dataSourceTarget"/>
                </bean>


                <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
                    <property name="entityManagerFactory" ref="entityManagerFactory"/>
                    <property name="dataSource" ref="dataSource"/>
                </bean>

                <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/>

                <bean id="genericDAO" class="myapp.api.dao.impl.GenericDAOImpl">
                    <constructor-arg>
                        <value>java.io.Serializable</value>
                    </constructor-arg>
                </bean>

                <bean id="springContextHolder" class="myapp.api.util.SpringContextHolder" factory-method="getInstance" />

        <bean id="executionInterceptor" class="myapp.api.listener.backoffice.ExecutionInterceptor" />

        <!-- JNDI-->
        <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"/>

        <!-- JMS -->
        <bean id="jmsQueueConnectionFactory"  class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiTemplate">
                <ref bean="jndiTemplate"/>
            </property>
            <property name="jndiName" value="${jms.jndi.qconnectionfactory}">

            </property>
        </bean>
        <bean id="myJMSConnectionFactory" class="com.api.model.vo.backoffice.OpenMqConnectionFactoryBean">
            <property name="imqAddressList" value="${jms.imq.url}" />
            <property name="imqDefaultUsername" value="${jms.imq.user}" />
            <property name="imqDefaultPassword" value="${jms.imq.password}" />
            <property name="imqHost" value="${jms.imq.host}" />
            <property name="imqPort" value="${jms.imq.port}" />
        </bean>

        <bean id="stuMessageListener" class="com.api.listener.backoffice.STUMessageListener" />
        <bean id="storeListener" class="com.api.listener.backoffice.StorableMessageListener"/>

        <bean id="executionInterceptor" class="com.api.listener.backoffice.ExecutionInterceptor" />

        <bean id="stuJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
            <property name="destinationName" value="STUInputQ"/>
            <property name="sessionTransacted" value="false"/>
            <property name="messageListener" ref="stuMessageListener" />
            <property name="concurrentConsumers" value="5" />
            <property name="maxConcurrentConsumers" value="100" />
            <property name="receiveTimeout" value="30000" />
            <property name="cacheLevelName" value="CACHE_NONE" />

        </bean>
        <bean id="storeJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
            <property name="destinationName" value="ArchiveQ"/>
            <property name="sessionTransacted" value="false"/>
            <property name="messageListener" ref="storeListener" />
            <property name="concurrentConsumers" value="5" />
            <property name="maxConcurrentConsumers" value="100" />
            <property name="receiveTimeout" value="30000" />
            <property name="cacheLevelName" value="CACHE_NONE" />

        </bean>

 </beans>
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="com" transaction-type="RESOURCE_LOCAL">
  </persistence-unit>
</persistence>
public class STUMessageListener implements javax.jms.MessageListener{
       @Autowired
       StoringService storingService;

       @Transactional
       public void onMessage(Message message) throws RuntimeException { 
           try {
                Object omsg = ((ObjectMessage) message).getObject();
                if (omsg instanceof StorableMessage) {
                     StorableMessage storableMessage = (StorableMessage) omsg;
                     //StorableMessage insert into Database
                     storingService.store(storableMessage); 

                   //jms logic here to send message to next queue (ArchiveQ)
           }
           catch (Throwable ex) {
                throw new RuntimeException(ex);
            }
   }

     @Service("storingService")
        public class StoringServiceImpl{

            @Autowired
            MessagesDAO messagesDAO;

            @Transactional
            public StorableMessage store(StorableMessage storableMessage) {
                messagesDAO.save(storableMessage);
            }

        }

    @Repository("messagesDAO")
    public class MessagesDAOImpl{
        private Class<T> type
        @PersistenceContext
        EntityManager entityManager;

        public void save(T object) {
           entityManager.persist(object);
        }

        public T findById(Serializable id) {
           return entityManager.find(type, id);
        }
    }
public class StorableMessageListener implements javax.jms.MessageListener {
    @Autowired
    MessageDAO messageDAO;

    @Transactional
    public void onMessage(Message message) throws RuntimeException {
          if (omsg instanceof StorableMessage) {
               //this is where null is returned for the Messages object 18% of the time
               //sleep thread by 1 second logic here helps eliminate the null Messages object
              //uses same MessageDAO as above 
              Messages msg = messageDAO.findById(storableMessage.getMessageKey());
          }
    }
我添加了一些逻辑来休眠线程,这确保了我在读取数据库时不会得到null。我真的不认为线程睡眠是一个长期的解决方案。你知道为什么在StorableMessageListener读取事务之前,STUMessageListener无法提交事务吗

依赖关系:

<?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:util="http://www.springframework.org/schema/util"
                xmlns:context="http://www.springframework.org/schema/context"
                xmlns:aop="http://www.springframework.org/schema/aop"
                xmlns:tx="http://www.springframework.org/schema/tx"
                xmlns:hz="http://www.hazelcast.com/schema/spring"
                xsi:schemaLocation="
                http://www.hazelcast.com/schema/spring
                http://www.hazelcast.com/schema/spring/hazelcast-spring-2.5.xsd
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/util
                http://www.springframework.org/schema/util/spring-util-3.0.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.0.xsd
                http://www.springframework.org/schema/tx
                http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

                <!-- Generic -->
                <context:annotation-config />
                <context:component-scan base-package="myapp.api" />
                <aop:aspectj-autoproxy/>

                <!-- JPA -->
                <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

                <tx:annotation-driven />

                <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

                <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                    <property name="dataSource" ref="dataSource" />
                    <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
                    <property name="persistenceUnitName" value="MyApp" />
                    <property name="jpaProperties">
                        <props>
                            <prop key="hibernate.use_sql_comments">true</prop>
                            <prop key="hibernate.generate_statistics">true</prop>
                            <prop key="hibernate.archive.autodetection">class</prop>
                            <prop key="hibernate.cache.use_second_level_cache">true</prop>
                            <prop key="hibernate.cache.provider_class">com.hazelcast.hibernate.provider.HazelcastCacheProvider</prop>
                            <prop key="hibernate.cache.use_query_cache">true</prop>
                            <prop key="hibernate.cache.use_minimal_puts">true</prop>
                        </props>
                    </property>
                </bean>


               <hz:hazelcast id="instance">
                    <hz:config>
                         //rest of Hazelast config maps here
                    </hz:config>
                </hz:hazelcast>

                <hz:hibernate-region-factory id="regionFactory" instance-ref="instance"/>

                <!-- Define JPA Provider Adapter -->
                <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <property name="showSql" value="true" />
                    <property name="generateDdl" value="true" />
                    <property name="databasePlatform" value="org.hibernate.dialect.OracleDialect" />
                </bean>

                <bean id="dataSourceTarget" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
                    <property name="URL" value="jdbc:oracle:thin:@server:1525:name" />
                    <property name="user" value="test" />
                    <property name="password" value="123" />
                    <property name="connectionCachingEnabled" value="true" />
                    <property name="connectionCacheProperties">
                        <props merge="default">
                            <prop key="MinLimit">5</prop>
                            <prop key="MaxLimit">50</prop>
                        </props>
                    </property>
                </bean>

                <bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
                    <property name="targetDataSource" ref="dataSourceTarget"/>
                </bean>


                <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
                    <property name="entityManagerFactory" ref="entityManagerFactory"/>
                    <property name="dataSource" ref="dataSource"/>
                </bean>

                <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/>

                <bean id="genericDAO" class="myapp.api.dao.impl.GenericDAOImpl">
                    <constructor-arg>
                        <value>java.io.Serializable</value>
                    </constructor-arg>
                </bean>

                <bean id="springContextHolder" class="myapp.api.util.SpringContextHolder" factory-method="getInstance" />

        <bean id="executionInterceptor" class="myapp.api.listener.backoffice.ExecutionInterceptor" />

        <!-- JNDI-->
        <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"/>

        <!-- JMS -->
        <bean id="jmsQueueConnectionFactory"  class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiTemplate">
                <ref bean="jndiTemplate"/>
            </property>
            <property name="jndiName" value="${jms.jndi.qconnectionfactory}">

            </property>
        </bean>
        <bean id="myJMSConnectionFactory" class="com.api.model.vo.backoffice.OpenMqConnectionFactoryBean">
            <property name="imqAddressList" value="${jms.imq.url}" />
            <property name="imqDefaultUsername" value="${jms.imq.user}" />
            <property name="imqDefaultPassword" value="${jms.imq.password}" />
            <property name="imqHost" value="${jms.imq.host}" />
            <property name="imqPort" value="${jms.imq.port}" />
        </bean>

        <bean id="stuMessageListener" class="com.api.listener.backoffice.STUMessageListener" />
        <bean id="storeListener" class="com.api.listener.backoffice.StorableMessageListener"/>

        <bean id="executionInterceptor" class="com.api.listener.backoffice.ExecutionInterceptor" />

        <bean id="stuJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
            <property name="destinationName" value="STUInputQ"/>
            <property name="sessionTransacted" value="false"/>
            <property name="messageListener" ref="stuMessageListener" />
            <property name="concurrentConsumers" value="5" />
            <property name="maxConcurrentConsumers" value="100" />
            <property name="receiveTimeout" value="30000" />
            <property name="cacheLevelName" value="CACHE_NONE" />

        </bean>
        <bean id="storeJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
            <property name="destinationName" value="ArchiveQ"/>
            <property name="sessionTransacted" value="false"/>
            <property name="messageListener" ref="storeListener" />
            <property name="concurrentConsumers" value="5" />
            <property name="maxConcurrentConsumers" value="100" />
            <property name="receiveTimeout" value="30000" />
            <property name="cacheLevelName" value="CACHE_NONE" />

        </bean>

 </beans>
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="com" transaction-type="RESOURCE_LOCAL">
  </persistence-unit>
</persistence>
public class STUMessageListener implements javax.jms.MessageListener{
       @Autowired
       StoringService storingService;

       @Transactional
       public void onMessage(Message message) throws RuntimeException { 
           try {
                Object omsg = ((ObjectMessage) message).getObject();
                if (omsg instanceof StorableMessage) {
                     StorableMessage storableMessage = (StorableMessage) omsg;
                     //StorableMessage insert into Database
                     storingService.store(storableMessage); 

                   //jms logic here to send message to next queue (ArchiveQ)
           }
           catch (Throwable ex) {
                throw new RuntimeException(ex);
            }
   }

     @Service("storingService")
        public class StoringServiceImpl{

            @Autowired
            MessagesDAO messagesDAO;

            @Transactional
            public StorableMessage store(StorableMessage storableMessage) {
                messagesDAO.save(storableMessage);
            }

        }

    @Repository("messagesDAO")
    public class MessagesDAOImpl{
        private Class<T> type
        @PersistenceContext
        EntityManager entityManager;

        public void save(T object) {
           entityManager.persist(object);
        }

        public T findById(Serializable id) {
           return entityManager.find(type, id);
        }
    }
public class StorableMessageListener implements javax.jms.MessageListener {
    @Autowired
    MessageDAO messageDAO;

    @Transactional
    public void onMessage(Message message) throws RuntimeException {
          if (omsg instanceof StorableMessage) {
               //this is where null is returned for the Messages object 18% of the time
               //sleep thread by 1 second logic here helps eliminate the null Messages object
              //uses same MessageDAO as above 
              Messages msg = messageDAO.findById(storableMessage.getMessageKey());
          }
    }
hibernate-core.3.3.2.GA

hibernate-entitymanager-3.4.0.GA

弹簧3.0.6.1释放

Java 1.5

弹簧配置:

<?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:util="http://www.springframework.org/schema/util"
                xmlns:context="http://www.springframework.org/schema/context"
                xmlns:aop="http://www.springframework.org/schema/aop"
                xmlns:tx="http://www.springframework.org/schema/tx"
                xmlns:hz="http://www.hazelcast.com/schema/spring"
                xsi:schemaLocation="
                http://www.hazelcast.com/schema/spring
                http://www.hazelcast.com/schema/spring/hazelcast-spring-2.5.xsd
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/util
                http://www.springframework.org/schema/util/spring-util-3.0.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.0.xsd
                http://www.springframework.org/schema/tx
                http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

                <!-- Generic -->
                <context:annotation-config />
                <context:component-scan base-package="myapp.api" />
                <aop:aspectj-autoproxy/>

                <!-- JPA -->
                <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

                <tx:annotation-driven />

                <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

                <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                    <property name="dataSource" ref="dataSource" />
                    <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
                    <property name="persistenceUnitName" value="MyApp" />
                    <property name="jpaProperties">
                        <props>
                            <prop key="hibernate.use_sql_comments">true</prop>
                            <prop key="hibernate.generate_statistics">true</prop>
                            <prop key="hibernate.archive.autodetection">class</prop>
                            <prop key="hibernate.cache.use_second_level_cache">true</prop>
                            <prop key="hibernate.cache.provider_class">com.hazelcast.hibernate.provider.HazelcastCacheProvider</prop>
                            <prop key="hibernate.cache.use_query_cache">true</prop>
                            <prop key="hibernate.cache.use_minimal_puts">true</prop>
                        </props>
                    </property>
                </bean>


               <hz:hazelcast id="instance">
                    <hz:config>
                         //rest of Hazelast config maps here
                    </hz:config>
                </hz:hazelcast>

                <hz:hibernate-region-factory id="regionFactory" instance-ref="instance"/>

                <!-- Define JPA Provider Adapter -->
                <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <property name="showSql" value="true" />
                    <property name="generateDdl" value="true" />
                    <property name="databasePlatform" value="org.hibernate.dialect.OracleDialect" />
                </bean>

                <bean id="dataSourceTarget" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
                    <property name="URL" value="jdbc:oracle:thin:@server:1525:name" />
                    <property name="user" value="test" />
                    <property name="password" value="123" />
                    <property name="connectionCachingEnabled" value="true" />
                    <property name="connectionCacheProperties">
                        <props merge="default">
                            <prop key="MinLimit">5</prop>
                            <prop key="MaxLimit">50</prop>
                        </props>
                    </property>
                </bean>

                <bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
                    <property name="targetDataSource" ref="dataSourceTarget"/>
                </bean>


                <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
                    <property name="entityManagerFactory" ref="entityManagerFactory"/>
                    <property name="dataSource" ref="dataSource"/>
                </bean>

                <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/>

                <bean id="genericDAO" class="myapp.api.dao.impl.GenericDAOImpl">
                    <constructor-arg>
                        <value>java.io.Serializable</value>
                    </constructor-arg>
                </bean>

                <bean id="springContextHolder" class="myapp.api.util.SpringContextHolder" factory-method="getInstance" />

        <bean id="executionInterceptor" class="myapp.api.listener.backoffice.ExecutionInterceptor" />

        <!-- JNDI-->
        <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"/>

        <!-- JMS -->
        <bean id="jmsQueueConnectionFactory"  class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiTemplate">
                <ref bean="jndiTemplate"/>
            </property>
            <property name="jndiName" value="${jms.jndi.qconnectionfactory}">

            </property>
        </bean>
        <bean id="myJMSConnectionFactory" class="com.api.model.vo.backoffice.OpenMqConnectionFactoryBean">
            <property name="imqAddressList" value="${jms.imq.url}" />
            <property name="imqDefaultUsername" value="${jms.imq.user}" />
            <property name="imqDefaultPassword" value="${jms.imq.password}" />
            <property name="imqHost" value="${jms.imq.host}" />
            <property name="imqPort" value="${jms.imq.port}" />
        </bean>

        <bean id="stuMessageListener" class="com.api.listener.backoffice.STUMessageListener" />
        <bean id="storeListener" class="com.api.listener.backoffice.StorableMessageListener"/>

        <bean id="executionInterceptor" class="com.api.listener.backoffice.ExecutionInterceptor" />

        <bean id="stuJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
            <property name="destinationName" value="STUInputQ"/>
            <property name="sessionTransacted" value="false"/>
            <property name="messageListener" ref="stuMessageListener" />
            <property name="concurrentConsumers" value="5" />
            <property name="maxConcurrentConsumers" value="100" />
            <property name="receiveTimeout" value="30000" />
            <property name="cacheLevelName" value="CACHE_NONE" />

        </bean>
        <bean id="storeJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
            <property name="destinationName" value="ArchiveQ"/>
            <property name="sessionTransacted" value="false"/>
            <property name="messageListener" ref="storeListener" />
            <property name="concurrentConsumers" value="5" />
            <property name="maxConcurrentConsumers" value="100" />
            <property name="receiveTimeout" value="30000" />
            <property name="cacheLevelName" value="CACHE_NONE" />

        </bean>

 </beans>
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="com" transaction-type="RESOURCE_LOCAL">
  </persistence-unit>
</persistence>
public class STUMessageListener implements javax.jms.MessageListener{
       @Autowired
       StoringService storingService;

       @Transactional
       public void onMessage(Message message) throws RuntimeException { 
           try {
                Object omsg = ((ObjectMessage) message).getObject();
                if (omsg instanceof StorableMessage) {
                     StorableMessage storableMessage = (StorableMessage) omsg;
                     //StorableMessage insert into Database
                     storingService.store(storableMessage); 

                   //jms logic here to send message to next queue (ArchiveQ)
           }
           catch (Throwable ex) {
                throw new RuntimeException(ex);
            }
   }

     @Service("storingService")
        public class StoringServiceImpl{

            @Autowired
            MessagesDAO messagesDAO;

            @Transactional
            public StorableMessage store(StorableMessage storableMessage) {
                messagesDAO.save(storableMessage);
            }

        }

    @Repository("messagesDAO")
    public class MessagesDAOImpl{
        private Class<T> type
        @PersistenceContext
        EntityManager entityManager;

        public void save(T object) {
           entityManager.persist(object);
        }

        public T findById(Serializable id) {
           return entityManager.find(type, id);
        }
    }
public class StorableMessageListener implements javax.jms.MessageListener {
    @Autowired
    MessageDAO messageDAO;

    @Transactional
    public void onMessage(Message message) throws RuntimeException {
          if (omsg instanceof StorableMessage) {
               //this is where null is returned for the Messages object 18% of the time
               //sleep thread by 1 second logic here helps eliminate the null Messages object
              //uses same MessageDAO as above 
              Messages msg = messageDAO.findById(storableMessage.getMessageKey());
          }
    }

尝试将insert方法的注释更改为

@事务性(传播=传播。需要\u新建)


这将在方法完成后立即提交插入。

它仍然为空,与该事务更改的金额相同。您更改了服务方法,对吗?比如->@Transactional(propagation=propagation.REQUIRES_NEW)公共存储消息存储(StorableMessage StorableMessage){messagesDAO.save(StorableMessage);}REQUIRES_NEW必须在StoringServiceImpl的方法中。为什么将“onMessage()”标记为@Transactional?你试过删除它吗?这是遗留代码,就是这样,我会尝试删除OK。您可以尝试从两个“onMessage”方法中删除它。如果仍然没有帮助,请在STUMessageListener.onMessage()中发布JMS逻辑。