了解EJB事务类型

时间:2012-09-13 08:46:57

标签: java transactions ejb

我的应用程序中有一些我无法理解的行为。我有1个有状态bean,1个无状态bean,我想从SFB的1个SLB方法(解析WEB页面)调用。没关系,但是SLB调用将JMS消息发送到另一个应用程序的业务方法,并且由于事务类型(REQUIRED),所有消息都被同时接收。

所以我已将sendind方法的事务类型更改为REQUIRES_NEW,但它是相同的,所有消息都是同时收到的。

通过将解析方法更改为REQUIRES_NEW,我以异步方式接收消息。那么如何解释这种行为?

总结:

SFB method -> REQUIRED

SLB method (parsing of WEB page, urls stored in String[]) -> REQUIRED

SLB method JMS -> REQUIRED

==> JMS messages are received synchronously



SFB method -> REQUIRED

SLB method -> REQUIRED

SLB method JMS -> REQUIRES_NEW

==> JMS messages are received synchronously



SFB method -> REQUIRED

SLB method -> REQUIRES_NEW

SLB method JMS -> REQUIRES_NEW

==> JMS messages are received asynchronously

我希望案例2能异步发送JMS消息......

感谢您的澄清

奥利弗

2 个答案:

答案 0 :(得分:3)

您没有显示您的代码,但我怀疑您从同一SLB实例的解析方法中调用SLB中的send方法。在这种情况下,方法调用是一个直接的方法调用,它不通过bean代理,因此完全忽略了send方法上的事务注释。

你有

SFB -> transactional proxy -> SLB -> SLB

你应该在哪里

SFB -> transactional proxy -> SLB -> transactional proxy -> SLB

最简单的方法是将send方法放在单独的SLB中。

答案 1 :(得分:0)

谢谢JB Nizet(没有快速回复,因为我必须等待8小时才能回复 - >我是StackOverflow的新手,需要声誉)

我已经测试了使用新SLB发送JMS消息,结果相同,但我的两个SLB是强耦合的,因为我将TopicPublisher和JMS消息传递给我的新测试EJB。

我刚测试在我的测试EJB中创建了TopicPublisher和消息,并且...它的工作正在进行中!

这是我的新EJB:

package boursorama.stateless;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;


@Stateless
@LocalBean
public class Test {

    @Resource(mappedName="jms/boursoramaTopicFactory")
    TopicConnectionFactory topicConnectionFactory;

    @Resource(mappedName="jms/boursoramaTopicDestination")
    Topic topic;

    private TopicConnection _topicConnection;
    private TopicSession _topicSession;
    private TopicPublisher _topicPublisher;

    @PostConstruct
    public void postConstruct(){

        try {
            _topicConnection = topicConnectionFactory.createTopicConnection();
            _topicSession = _topicConnection.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
            _topicPublisher = _topicSession.createPublisher(topic);     
        } catch (JMSException e) {          
            e.printStackTrace();
        }       
    }

    @PreDestroy
    public void preDestroy(){
        try {
            _topicConnection.close();   
            _topicConnection = null;        
        } catch (JMSException e) {          
            e.printStackTrace();
        }    
    }

    public Test() {
        // TODO Auto-generated constructor stub
    }



    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void test(){
        try {
            Message m = _topicSession.createObjectMessage();                
            _topicPublisher.send(m);
        } catch (JMSException e) {          
            e.printStackTrace();
        }
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void test2(TopicPublisher to, Message m){
        try {
            to.send(m);
        } catch (JMSException e) {          
            e.printStackTrace();
        }
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void test3(Message m){
        try {
            _topicPublisher.send(m);
        } catch (JMSException e) {          
            e.printStackTrace();
        }
    }



}

当我调用test()或test3()时,我会异步接收所有消息,但test2()会一起发送消息。

如果我理解的话,当在方法之间共享某些资源(使用@Resource)时,我们无法在同一个EJB内部或在外部管理事务(使用REQUIRES_NEW)?当然,我有这种行为来尊重事务隔离吗?

再次感谢您

奥利弗