2012-12-31 23 views
9

Ho iniziato a utilizzare le transazioni a livello di metodo di Guice come descritto here. Ho un messaggio comeGuice @Transactional non avvia una transazione

@Inject 
private EntityManager entityManager; 

@Transactional 
public UserSession createSession(User user, String browser) { 
    UserSession session = new UserSession(user, browser); 
    entityManager.persist(session); 
} 

Dalla breve descrizione ho pensato che dovrebbe essere sufficiente. Ma ottengo un errore perché nessuna transazione è stata avviata. Funziona solo se inizio e me lo commetto da solo.

L'oggetto viene creato da Guice all'avvio dell'applicazione in un inizializzatore. la stessa istanza viene utilizzata per ogni richiesta.

Perché non funziona?

risposta

6

@Transactional metodo annotazioni funzionano attraverso AOP, in cui Guice soddisfa una richiesta di Foo creando un oggetto proxy che intercetta le chiamate metodo annotato e (opzionalmente) li inoltra all'oggetto effettivo. Assicurarsi che il seguente requisito:

  1. È stato creato l'oggetto con il metodo @Transactional attraverso Guice, dal momento che Guice altrimenti non avrà alcuna possibilità di fornire al proxy invece.

  2. Né la classe né il metodo sono contrassegnati con final, poiché AOP non può sovrascrivere quelli facilmente.

  3. Hai installato JpaPersistModule o qualche altra forma di PersistModule. Nota da quel codice sorgente che questo modulo è effettivamente ciò che lega l'MethodInterceptor all'annotazione @Transactional.

Se questo non si adatta esattamente le vostre esigenze, ricorda che si può sempre andare con il AOP documentation di scrivere il proprio metodo di intercettazione. In bocca al lupo!

+0

"Né l'oggetto né il metodo sono contrassegnati come final" Non dovrebbe essere "Né la * classe * né il metodo sono contrassegnati come finali"? –

+0

Yup, slip of the mind. Fisso. –

2

Dopo aver controllato di nuovo tutto, non ha funzionato. La parte divertente è che ha funzionato nel mezzo, ma solo ogni cento volte.

Dopo alcuni test aggiuntivi ho scoperto che ho bisogno di ricreare le classi su ogni richiesta. Prima li ho appena creati all'avvio dell'applicazione. Ora sembra funzionare perfettamente.

Grazie per i suggerimenti mi ha aiutato a indagare ulteriormente.

0

Ho avuto questo problema nella seguente situazione, così ho pensato che avrei posto la mia soluzione anche qui:

BusinessLogic richiede due argomenti del costruttore: MyDao, che ho potuto teoricamente ottenere da Guice, e qualche altro oggetto che potrei non ottenere da guice.
Così ho creato un BusinessLogicProvider (extends AbstactProvider), ma non è utilizzato con bind(BusinessLogic.class).toProvider(BusinessLogicProvider)). Ora ho solo associare il BusinessLogicProvider come qualsiasi tipo Guice-servito: bind(BusinessLogicProvider.class);

Dentro la mia classe BusinessLogicProvider ora posso usare @Inject su un private Provider<MyDao> daoProvider;

In seguito, nel metodo di 's il BusinessLogicProviderpublic BusinessLogic get(), posso quindi chiamare BusinessLogic Costruttore con i due argomenti richiesti: daoProvider.get() e l'altro oggetto non riesco a ottenere da guice.

la trappola: quando la@Inject Ed private Provider<MyDao> daoProvider; della mia BusinessLogicProvider non è di tipo Provider<MyDao> (ma simpy di tipo MyDao), non funzionerà.
Anche se lo @Inject ed il MyDaosarebbero provenire da guizzi, guice deve crearne uno nuovo ogni volta che si instanzia BusinessLogic.

1

Ho riscontrato un problema simile al tuo ed è stato risolto passando da @ javax.transaction.Transactional a @ com.google.inject.persist.Transactional. Apparentemente Guice-Persist non supporta l'annotazione @Transactional dall'API Java Transaction.