2012-02-03 7 views
5

Ho un'applicazione sandbox Seam 3 che utilizza JBoss 7, Hibernate come implementazione JPA predefinita e come JSF come front-end web.JPA/Hibernate non emette alcun UPDATE sul commit nell'ambiente EJB/Seam

Ho il problema, che SQL UPDATE è ingerito di default.

mio EJB stateful portata conversazione mantiene un esteso con scope EntityManager e una sola entità, transazioni gestite container (richiede nuove)

  1. L'EntityManager viene iniettato
  2. L'EJB utilizza il EM per caricare l'Entity e mantiene in un campo
  3. applicazione JSF accede al EJB e la sua entità, cambia un campo stringa
  4. calles un'applicazione JSF metodo "Save" in EJB
  5. in save() Controllo, se il campo Entities è stato modificato -> è stato modificato correttamente
  6. Non faccio altro, il container esegue la transazione dopo che save() è terminato.
  7. Problema: non viene eseguito alcun aggiornamento SQL sul DB.

Se estendo save() da:

a) entityManager.contains (entità) l'aggiornamento viene eseguito come previsto (risultato è "true")

O

b) entityManager.persist (entità) UPDATE viene eseguito come previsto

Q: Per quanto ne so, le specifiche non sono né a) né b), poiché l'Entità rimane gestita durante l'intero processo. Non capisco, perché a) ha un effetto sul risparmio. Posso immaginare il b) ha un effetto sul salvataggio, ma non dovrebbe essere richiesto, dovrebbe?

Qualsiasi spiegazione è la benvenuta.

Ecco il mio EJB:

@Named 
@ConversationScoped 
@Stateful 
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
public class LanguageBean { 

    @PersistenceContext(type = PersistenceContextType.EXTENDED) 
    private EntityManager em; 
    @Inject 
    private UserTransaction transaction; 

    private Language value; 

    @Inject 
    Conversation conversation; 

    public LanguageBean() { 
     super(); 
    } 

    @Begin 
    public void selectLanguage(Long anId) { 
     conversation.setTimeout(10 * 60 * 1000); 
     if (anId != null) { 
      value = em.find(Language.class, anId); 
     } 
    } 

    @BeforeCompletion 
    public void transactionComplete(){ 
     System.out.println("transactionComplete"); 
    } 

    public Language getValue() { 
     return value; 
    } 

    @Produces 
    @Named 
    @ConversationScoped 
    public Language getLanguage() { 
     return getValue(); 
    } 

    public void setValue(Language aValue) { 
     value = aValue; 
    } 

    @End 
    public String save() { 
//  displays the changed attribute: 
     System.out.println("save code: "+value.getCode()); 

//  why is either this required: 
//  boolean tempContains = em.contains(value); 
//  System.out.println("managed: "+tempContains); 

//  or: why is persist required: 
     em.persist(value); 
     return "languages?faces-redirect=true"; 
    } 

    @End 
    public String cancel() throws SystemException { 
     transaction.setRollbackOnly(); 
     return "languages?faces-redirect=true"; 
    } 

} 
+0

ho scoperto entityManager.flush() risolve anche il problema. Ma non capisco perché questo sembra essere richiesto. Dalla specifica JPA: "Quando la transazione JTA viene eseguita, il provider deve scaricare lo stato di tutte le entità modificate nel database ". – user1187037

+0

forse da qualche parte la modalità Flush della sessione di ibernazione è impostata su nessuna? – Firo

risposta

0

tenta di aggiungere @Remove annotazioni sui metodi annotati da @End.

A mio parere l'annotazione @End non determina la distruzione del bean. Quindi il contesto di persistenza è attivo anche dopo l'esecuzione di save() e il suo contenuto non può essere scaricato nel database.

1

La mia esperienza è in gran parte con Seam-2, ma dovrebbe essere ugualmente applicabile qui.

La conversazione e la sessione JPA sono disaccoppiate nella giuntura per il semplice motivo che una fine di conversazione non può comportare il salvataggio dell'entità.

Ad esempio, un'azione di annullamento una conversazione corsa lunga finirebbe la conversazione (poiché non v'è alcuna ragione per mantenere la conversazione più)

Considerando che si sta facendo un rollback sulla annullare nel tuo esempio, si sembrerebbe logico che tu debba chiamare un flush come suggerito da @ user1187037 (teoricamente un commit ma non credo sia permesso)

Penso che ci potrebbe essere stata una configurazione che potevi impostare in modo che fosse a filo alla fine della conversazione, ma potrei sbagliarmi.

In ogni caso, http://javalangblog.blogspot.co.uk/2010/04/flush-mode-conversation.html sembra suggerire una soluzione

Speranza che aiuta.

EDIT: È possibile configurare la modalità di colore per ogni conversazione utilizzando XML

<begin-conversation join="true" flush-mode="COMMIT" /> 

e utilizzando le annotazioni

@Begin(flushMode=COMMIT) 

Tenete a mente però che una conversazione può @End senza che sia esplicitamente definito. Se un utente partecipa alla conversazione, apporta modifiche alle entità e quindi abbandona la conversazione, si chiuderà automaticamente dopo un timeout. Se non ricordo male, questo farà sì che eventuali modifiche vengano commesse nel caso precedente.

Riferimenti:

http://docs.jboss.org/seam/3/persistence/3.0.0.Alpha1/reference/en-US/html_single/#d0e249 http://docs.jboss.org/seam/3/latest/api/org/jboss/seam/persistence/FlushModeType.html