0
public void postPessoa() {
    savePessoa();
    initializePessoa();
}

@Transactional(rollbackOn = {Exception.class})
public void savePessoa() {
    pessoa = getEntityManager().merge(pessoa);
}

If I call postPessoa() I got TransactionRequiredException in merge(), but if I call savePessoa() directly from JSF it works, and I didn't understand why this behavior.

JSF:

<p:commandButton id="btnSalvar" value="Salvar" action="#{pessoasController.savePessoa}"/>

<p:commandButton id="btnSalvar" value="Salvar" action="#{pessoasController.postPessoa}"/>
Kukeltje
  • 12,223
  • 4
  • 24
  • 47
Guilherme Bernardi
  • 490
  • 1
  • 6
  • 18
  • This is effectively not a JSF question. Same would have happend if you would have created a good unittest – Kukeltje May 11 '18 at 18:07
  • Probably, but I want to understand why calling annotated method directly from jsf change the behavior of Transactional annotation. – Guilherme Bernardi May 11 '18 at 18:14
  • It is not about calling it directly from jsf it is about calling it directly period. See the answer. Btw are you using spring or cdi? Answer is right both for spring and cdi – Kukeltje May 11 '18 at 18:47
  • I understand. I'm using CDI, but I'll be honest I'm asking because I don't know if my error is in jsf calling, in transactional or in my jpa control. I search a lot before ask here... – Guilherme Bernardi May 11 '18 at 20:11
  • That is why I mentioned a unit test. Yo can then exclude things. JSF in this case – Kukeltje May 11 '18 at 20:32
  • and the answer IS the answer to your question. Maybe not to your other problem but it is to this one – Kukeltje May 11 '18 at 20:34
  • I solved... but I think I just did a "hack"... But I'm almost sure that isn't the best practice. So actionListener executes first the method with transaction and action the other one... – Guilherme Bernardi May 11 '18 at 20:38

1 Answers1

0

You have to add

@Transactional

...on class level OR on postPessoa(), too.

from spring-doc:

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. @PostConstruct.

xerx593
  • 12,237
  • 5
  • 33
  • 64
  • 1
    but it is not propagated, when "calling this" ...that's why OR – xerx593 May 11 '18 at 18:06
  • @MạnhQuyếtNguyễn That is what Xerx593 stated. Thing is that if it is on a method it has to be a method that is called from outside the bean – Kukeltje May 11 '18 at 18:10
  • Ah ha, I was oversighted. His method was called within a class. Nice catch – Mạnh Quyết Nguyễn May 11 '18 at 18:12
  • @xerx593 but if I add Transactional in postPessoa(), the method initializePessoa() will be in the same transaction context, and that isn't what I want or am I wrong? – Guilherme Bernardi May 11 '18 at 18:12
  • aha!? (a second tx-context!?) you want to mix? (please explain ...sounds [tough..impossible]) – xerx593 May 11 '18 at 18:14
  • ...no, it's easy! with [2 tx-managers](https://stackoverflow.com/a/4423260/592355), you must mix/call them from "another bean" (a controller or something)! – xerx593 May 11 '18 at 18:18
  • thanks @xerx593, but I think that isn't what I need. I get into this issue after trying to initialize Lazy entities after a merge. When I call postPessoa() I want to merge and call initializePessoa() which is responsible to fetch all the lazy objects, but if I use initializePessoa() in a transaction context setListX() give me a error because hibernate identify as a change in entity. Maybe my problem isn't in transactional, but I'm really in doubt. – Guilherme Bernardi May 11 '18 at 20:15