2012-02-07 77 views
0

内处理队列中的事件我使用一个交易代理包装服务,我applicationContext.xml中包含:Spring MVC的控制器交易

<bean id="someService" 
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
    <property name="transactionManager" ref="transactionManager" /> 
    <property name="target" ref="someServiceImpl" /> 
    <property name="transactionAttributes"> 
     <props> 
      <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> 
      <prop key="create*">PROPAGATION_REQUIRED</prop> 
     </props> 
    </property> 
</bean> 


<bean name="someServiceImpl" class="impl.serviceImpl"> 
    <property name="dataDao" ref="dataDao" /> 
    <property name="eventQ" ref="eventQJMSTemplate"></property> 
</bean> 

文物被定义为队列:

<bean id="eventQJMSTemplate" class="org.springframework.jms.core.JmsTemplate"> 
    <property name="connectionFactory" ref="cachingMsgConnectionFactory" /> 
    <property name="defaultDestination" ref="newEventQ" /> 
</bean> 

<bean id="cachingMsgConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory" > 
    <property name="targetConnectionFactory" ref="msgConnectionFactory" /> 
    <property name="sessionCacheSize" value="10"/> 
</bean> 

<bean id="msgConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory" > 
    <property name="brokerURL" value="tcp://localhost:61616"/> 
</bean> 

该服务具有操作

public void create(Object obj) 
{ 
    dataDao.createAndSave(obj); 
    eventQ.send(new NewMessageCreator(obj.getId()); 

} 

消息处理程序被定义为

<bean id="newEventProcessor" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 
    <property name="connectionFactory" ref="cachingMsgConnectionFactory"/> 
    <property name="destination" ref="newEventQ"/> 
    <property name="messageListener" ref="newEventListener" /> 
</bean> 

<bean id="newProjectEventListener" class="messages.NewEventHandler"> 
    <property name="dataDao" ref="dataDao" /> 
</bean> 

消息处理程序的实现:

public class NewEventHandler implements MessageListener 
{ 
@Override 
public void onMessage(Message message) 
{ 
    Long objId; 
    if (message instanceof MapMessage) 
    { 
     try 
     { 
      MapMessage eventMsg = (MapMessage) message; 
      objId = eventMsg.getLong("objectId"); 
     } 
     catch (JMSException ex) 
     { 
      log.error("Error parsing new event.", ex); 
      throw new RuntimeException(ex); // TODO error handling 
     } 


      dataDao.find(objId); 
      //ERROR 
      // This fails as the object is still in the save transaction 

    } 
} 
} 

对象的GET操作失败,因为交易尚未完成。事务完成后将消息发送到队列的最佳方式是什么? 我必须在创建方法中执行此操作,因为这是进入服务的公共接口。

所有组件都在一个Tomcat实例运行。

Thankss

回答

0

如果我理解正确的,你有保存在数据库中的一些数据,并发送消息的事务。消息的接收者试图从数据库中读取数据,但没有找到它,因为收到了该消息,但发件人的事务尚未提交。

你是在一个情况下,你需要一个支持XA(2阶段提交)事务管理器,其招收的数据库和JMS代理到同一个全局事务。这样,对数据库的写入和消息的发送都是以原子方式执行的,并且如果数据库写入尚未完成并且成功,则无法发送消息。

有自由这样的事务管理器,像Bitronix,Atomikos公司或JBoss的TM。

+0

是的,没错。我想要实现这个的最初方式是将消息队列生产者作为AOP方面实现,并在事务完成后添加它。 – user1132294 2012-02-07 10:41:50

+0

这有两个缺点:它使得代码更难理解(特别是如果消息内容取决于方法内部完成的内容),并且它不处理数据库中的提交工作的情况,但是发送消息失败。您失去了交易的ACID功能。 – 2012-02-07 11:42:06