Reputation: 3165
I have some behaviour in my application that I can't understand. I have 1 stateful bean, 1 stateless bean and I want to call from SFB 1 method of SLB (parsing of WEB pages). It's OK but SLB calls business method that send JMS message to another application and all messages are received at same time due to transaction type (REQUIRED).
So I've changed transaction type of my sendind method to REQUIRES_NEW but it's the same, all messages are received at same time.
By changing parsing method to REQUIRES_NEW, I receive messages asynchronously. So how can this behaviour be explained ?
To summarize :
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
I expected case 2 to send JMS messages asynchronously...
Thanks for clarification
Olivier
Upvotes: 1
Views: 688
Reputation: 3165
Thank you JB Nizet (didn't reply quickly because I have to wait for 8 hours before replying -> I'm new in StackOverflow, need reputation)
I've already test sending JMS messages using new SLB and it was the same result but my two SLB were strongly coupled because I passed TopicPublisher and JMS message to my new testing EJB.
I just tested to create TopicPublisher and message inside my test EJB and...it's work !
Here is my new 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();
}
}
}
When I call test() or test3() I receive all messages asynchronously but test2() send messages all together.
If I understand well, we can't manage transactions (with REQUIRES_NEW) inside same EJB or outside when some resources are shared between methods (with @Resource) ? Surely I have this behaviour to respect transaction isolation ?
Thank you again
Olivier
Upvotes: 0
Reputation: 691635
You don't show your code, but I suspect that you call the send method in your SLB from the parse method of the same SLB instance. In that case, the method call is a direct method call, which doesn't go through the bean proxy, and thus the transactional annotation on the send method is completely ignored.
You have
SFB -> transactional proxy -> SLB -> SLB
where you should have
SFB -> transactional proxy -> SLB -> transactional proxy -> SLB
The simplest way is to put the send method in a separate SLB.
Upvotes: 3