|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Senior Member
Iscritto dal: Dec 2002
Messaggi: 3359
|
[spring + hibernate] @Transactional
Ciao a tutti, qualcuno qui mi sa dire a cosa serve esattemnte @Transactional usato all'interno di un DAO?
Mi pare di aver capito che indica che quel metodo fa partira una transazione, solo che ho fatto alcune prove e mi sembra che il tutto funzioni anche senza quell'annotazione. Magari avete qualche esempio facile facile che mette il luce le doti e l'utilità di questa classe? Grazie |
![]() |
![]() |
![]() |
#2 |
Member
Iscritto dal: May 2009
Messaggi: 129
|
Ciao.
Ti posto questo link che secondo me è molto esplicativo: http://monstersandwich.blogspot.com/...lications.html Credo comunque che tu non abbia impostato Spring per gestire la transazionalità attraverso le Annotation. Per utilizzare questa modalità dovresti avere nel tuo file di configurazione di spring questa occorrenza: Codice:
<tx:annotation-driven transaction-manager="transactionManager"/> Poi attraverso gli attributi di @Transactional definisci anche il comportamento della transazione (Required , Required New etc etc). Ricorda che in questo modo la transazione inizia (begin) all'inizio del metodo e si conclude (commit) alla fine del metodo stesso. In caso di eccezione durante l'esecuzione del metodo viene effettuato il rollback. Di solito l'annotation @Transactional viene utilizzata a livello di metodo di business e non al livello DAO,ma questa è solo un'indicazione. Ciao |
![]() |
![]() |
![]() |
#3 | |
Senior Member
Iscritto dal: Dec 2002
Messaggi: 3359
|
Quote:
![]() Prima di papparmi il link che mi hai dato ti volevo fare una domandina veloce. Solitamente (diciamo quando ho voglia di fare le cose fatte meglio ![]() Ecco, in questo service layer difficilmente un'operazione si conclude interessanto solo un DAO, anzi quasi mai direi, ma le operazioni sono intereazioni di metodi dei vari DAO. In questo caso la transazione la faccio iniziare all'inizio ( ![]() ![]() Se ho capito bene con spring mi basta annotare il metodo di tale macro-operazione con @Transactional (ancora non so in che forma me le andrò a vedere per bene) e fa tutto da solo? Aaaahh mi stavo dimenticando la super domandona della serata: se non metto mai @Transactional cosa succede? Come fa a funzionare tutto ugualmente? Hibernate senza un beginTransaction lancia delle eccezioni... Ultima modifica di MEMon : 28-10-2010 alle 23:09. |
|
![]() |
![]() |
![]() |
#4 |
Member
Iscritto dal: May 2009
Messaggi: 129
|
mmmm..immagino tu stia cercando di costruire una classica web-application multi-livello strutturata in tre livelli principali:
PRESENTATION: che presenta la logica di interazione con l'utente (jsp o similia) BUSINESS: che contiene i service che appunto espletano i servizi. PERSISTENCE: che offre le funzionalità di accesso alla base dati tramite i classici DAO. Non ho ben capito cosa intendi per "ulteriore strato" tra BUSINESS layer(service) e PERSISTENCE layer(Dao). Quelli che tu chiami service di solito sono i componenti che compongono il business layer. Ad ogni modo hai avuto un'intuizione giusta: La transazionalità,come ho accennato prima,di solito viene gestita a livello di SERVICE piu che a livello di DAO,in quanto un servizio per espletare il suo compito,sicuramente effetturà molteplici operazioni sulla base dati sottostante(operazioni che sono corrispondenti alle chiamate DAO del persistence layer)che devono avvenire nello stesso contesto transazionale. Inserendo @Transactional e specificando i suoi attributi si occupa di tutto Spring,e per te è completamente trasparente Se utilizzi il metodo delle annotation e non specifichi @Transactional credo (ma non ne sono certo) che di default lo aggiunga Spring. Ultima modifica di javacomelava : 28-10-2010 alle 23:26. |
![]() |
![]() |
![]() |
#5 | |
Senior Member
Iscritto dal: Dec 2002
Messaggi: 3359
|
Quote:
Se non uso transactional come si comporta spring? Ho fatto alcune prove e sembra andare lostesso, come fa? |
|
![]() |
![]() |
![]() |
#6 | |
Member
Iscritto dal: May 2009
Messaggi: 129
|
Quote:
1. Utiizzi la modalità dichiarativa tramite ANNOTATION: Codice:
<tx:annotation-driven transaction-manager="transactionManager"/> In questo caso credo (ma controlla per sicurezza) che Spring aggiunga automaticamente a livello di classe (e quindi tutti i metodi della classe) l'annotation in questione. 2. Utilizzi la modalitò dichiarativa tramite XML Allora nel configuration-file di Spring avrai qualcosa del genere: Codice:
<bean id="provaTransacationalService" class=""it.prova.me.ProvaTransactionalService"> <property name="transactionManager" ref="transactionManager" /> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="provaMetodo1" /> <tx:method name="provaMetodo2" /> ....... </tx:attributes> </tx:advice> Codice:
public class ProvaTransactionService implements ProvaTransactionalServiceInterface{ private DataSourceTransactionManager transactionManager; public DataSourceTransactionManager getTransactionManager() { return transactionManager; } public void setTransactionManager(DataSourceTransactionManager transactionManager) { this.transactionManager = transactionManager; } public void provaMetodo1(){ } public void provaMetodo2(){ } } 3. In piu puoi anche decidere di gestire PROGRAMMATICAMENTE la transazionalità (ovvero a livello di codice tramite TransactionTemplate di Spring che ti da la possibilità di utilizzare metodi come begin() commit() etc etc) 4. Se non specifichi nessuna gestione delle transazioni credo che Spring lanci un eccezione,ma anche questo non mi sento di dartelo per certo! Il discorso comunque è molto lungo e compesso,ti consiglio di googlare un pò,sicuramente troverai info a vagonate! Ciao |
|
![]() |
![]() |
![]() |
#7 | ||
Senior Member
Iscritto dal: Dec 2002
Messaggi: 3359
|
Quote:
Quote:
Credo di focalizzarmi sull'uso della annotazioni, le trovo comodissime. Grazie ancora mi sei stato di grande aiuto! |
||
![]() |
![]() |
![]() |
#8 |
Member
Iscritto dal: May 2009
Messaggi: 129
|
Beh gestire le transazione programmaticamente non significa tornare indietro. Sicuramente per applicazioni non estremamente complesse,lasciare che il container Spring si occupi delle transazioni,è la strada da seguire.
Prova a considerare però un'applicazione molto strutturata,potresti avere bisogno oppure semplicemente preferire una gestione "manuale" delle transazioni,cosi' da avere pieno controllo sul codice scritto! Spring ti da semplicemente la possibilità di farlo! Altro consiglio che mi sento di darti è quello di continuare a utilizzare il pattern DAO per disaccoppiare lo strato di BUSINESS dallo strato di PERSISTENZA. Il risultato stà in un codice piu chiaro,leggibile e indipendente(che si traduce in un'alto grado di manutenibilità per interventi futuri). Ciao! |
![]() |
![]() |
![]() |
#9 | |
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
![]() |
![]() |
![]() |
#10 | |
Senior Member
Iscritto dal: Dec 2002
Messaggi: 3359
|
Quote:
Hibernate già separa il livello di persistenza da quello di servizio. Ovviamente se si pensa che "un giorno" si cambierà la tecnologia usata, tipo da ORM -> JDBC allora ok è necessario qualcosa che astrae ancora di più, come un DAO appunto, ma diciamocelo, in quanti realmente lo han mai fatto / faranno? |
|
![]() |
![]() |
![]() |
#11 | ||
Member
Iscritto dal: May 2009
Messaggi: 129
|
Quote:
Quote:
La differenza che introduce un nuovo layer,come quello di persistenza attraverso i DAO,è un'astrazione a livello architetturarle. Per farla semplice: BUSINESS e PERSISTENCE ASSIEME ---> i tuoi metodi di business presenteranno righe di codice correlate all'accesso alla base dati. Non hai alcun tipo di disaccoppiamento! Mettiamo sempre il caso che l'applicazione sia molto strutturata,che succede quando domani dovrai risolvere un'eventuale problema????? Che succede se dovrai integrare con nuove funzionalità ???? Succede che dovrai modificare i tuoi metodi di business con enormi possibilità che queste modifiche si ripercuotano su altre funzionalità! Impensabile quindi per un'applicazione cosiddetta "enterprise". Tutto questo nonostante l'utilizzo di un ORM come hibernate il cui compito è solo quello di astrarre dalla base dati sottostante,non di dividere architetturalmente due parti diverse di un'applicazione! BUSINESS e PERSISTENCE disaccoppiati ---> Ogni modulo dell'applicazione è specializzato! I metodi che devono svolgere le operazioni di business conoscono solo le interfaccie dei metodi che devono svolgere le operazioni di accesso ai dati (specializzazione delle funzionalità). Se domani dovrai modificare un tuo DAO,non sporcherai necessariamente i moduli di business che utilizzando quel DAO. E ti assicuro che ci sarebbero altri 1000 buoni motivi per cui vale la pena perdere un pò piu di tempo in analisi e sviluppo per strutturare un'applicazione enterprise affinche sia il piu modulare possibile(testing,performance oltre che manutenibilità e scalabilità). Ovviamente,se devi fare un programmino che fa le addizioni e le sottrazioni,puoi anche evitare di scrivere i DAO ![]() Saluti,sperando di non essermi dilungato troppo in chiacchiere! |
||
![]() |
![]() |
![]() |
#12 | |
Senior Member
Iscritto dal: Dec 2002
Messaggi: 3359
|
Quote:
![]() Infatti il pattern DAO, in simbiosi con un ORM, trova posto quando si pensa di dover cambiare la tecnologia che interagisce con la base di dati, ma utilizzando un ORM già questo è possibile farlo cambiando il file di configurazione di hibernate e i driver di connessione... quindi... anche perchè la verità è che se si è pensato di sfruttare le potenzialità di un ORM, difficilmente si cambia strada in seguito. E sarei curioso di sapere a quanti è mai capitato, sopratutto in ambito lavorativo. E' ovvio che qualcosa che raccolga i metodi che accedono al db si fa, ma più che altro per evitare codice rindondante e per la mantenibilità. Ma da qui a dire che un pattern DAO serve... ne passa secondo me. Dammi due secondi ti scrivo un esempietto e vedrai che l'unica pecca che troverai sarà "ma se un giorno vorrai cambiare la tecnologia ecc ecc" Ultima modifica di MEMon : 29-10-2010 alle 11:55. |
|
![]() |
![]() |
![]() |
#13 |
Senior Member
Iscritto dal: Dec 2002
Messaggi: 3359
|
Questa è una classe "base" che crea netbeans automaticamente, è da rivedere un attimo ma per l'esempio va più che bene, racchiude i metodi crud, e ovviamente sarà qui che si aggiungeranno le varie operazioni, ad esempio di ricerca, relative alla entity "Item".
Codice:
public class ItemJpaController { private EntityManagerFactory emf=null; public ItemJpaController() { emf=Persistence.createEntityManagerFactory("ShootingRangePU"); } public EntityManager getEntityManager() { return emf.createEntityManager(); } public void create(Item item) { EntityManager em=null; try { em=getEntityManager(); em.getTransaction().begin(); em.persist(item); em.getTransaction().commit(); } finally { if(em!=null) { em.close(); } } } public void edit(Item item) throws NonexistentEntityException, Exception { EntityManager em=null; try { em=getEntityManager(); em.getTransaction().begin(); item=em.merge(item); em.getTransaction().commit(); } catch(Exception ex) { String msg=ex.getLocalizedMessage(); if(msg==null||msg.length()==0) { Long id=item.getId(); if(findItem(id)==null) { throw new NonexistentEntityException("The item with id "+id+" no longer exists."); } } throw ex; } finally { if(em!=null) { em.close(); } } } public void destroy(Long id) throws NonexistentEntityException { EntityManager em=null; try { em=getEntityManager(); em.getTransaction().begin(); Item item; try { item=em.getReference(Item.class, id); item.getId(); } catch(EntityNotFoundException enfe) { throw new NonexistentEntityException("The item with id "+id+" no longer exists.", enfe); } em.remove(item); em.getTransaction().commit(); } finally { if(em!=null) { em.close(); } } } public List<Item> findItemEntities() { return findItemEntities(true, -1, -1); } public List<Item> findItemEntities(int maxResults, int firstResult) { return findItemEntities(false, maxResults, firstResult); } private List<Item> findItemEntities(boolean all, int maxResults, int firstResult) { EntityManager em=getEntityManager(); try { Query q=em.createQuery("select object(o) from Item as o"); if(!all) { q.setMaxResults(maxResults); q.setFirstResult(firstResult); } return q.getResultList(); } finally { em.close(); } } public Item findItem(Long id) { EntityManager em=getEntityManager(); try { return em.find(Item.class, id); } finally { em.close(); } } public int getItemCount() { EntityManager em=getEntityManager(); try { Query q=em.createQuery("select count(o) from Item as o"); return ((Long)q.getSingleResult()).intValue(); } finally { em.close(); } } } Codice:
public class ItemJpaDAO extends AbstactItemDAO<Item, Long> implements ItemDAO{ //qui i vari metodi sopracitati } |
![]() |
![]() |
![]() |
#14 |
Member
Iscritto dal: May 2009
Messaggi: 129
|
Ciao
La differenza sta nel fatto che in questo modo,se un domani dovrai effettuare modifiche sulle classi che si occupano di persistenza(del tipo ItemJpaController) queste modifiche si ripercuoteranno sull'implementazione dei service di business che dovranno essere allineate alle nuove implementazioni. Invece utilizzando il pattern dao (e in generale sfruttadno la programmazione per interfacce) crei una divisione fisica tra il layer di business e il layer di persistenza. Un service di business conoscerà solo l'INTERFACCIA del Dao che usa e non la sua implementazione. L'ovvia conseguenza è che il tuo strato di business potrà rimanare completamente invariato anche in caso di modifiche al layer di persistenza! Bella robba se immagini un sistema fatto da centina di servizi e migliaia di righe di codice. Ti consiglio un'altro link che secondo me fa un ottimo sunto ad alto livello di come andrebbe strutturata un'applicazione multi-layer. E' un tutorial su Spring e Hiberante(molto carino) ma l'introduzione affronta proprio questa questione: http://www2.mokabyte.it/cms/article....11033_0f36c78a Saluti |
![]() |
![]() |
![]() |
#15 | |
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
![]()
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
![]() |
![]() |
![]() |
#16 |
Member
Iscritto dal: May 2009
Messaggi: 129
|
Eheheh....mokabyte secondo me è una miniera d'oro,soprattutto per chi si comincia ad affacciare a java e tecnologie correlate!
|
![]() |
![]() |
![]() |
#17 |
Senior Member
Iscritto dal: Dec 2002
Messaggi: 3359
|
Riuppo questo thread, anche se l'argomento è leggermente cambiato, ma sempre di spring+hibernate si tratta.
Sto cercando di automatizzare il caricamento dei DAO, per evitare quindi di inserirli ogni volta all'interno del file xml di spring. A questo scopo mi pare di aver capito che quello che fa per me è l'annotazione @Component(e derivati, @Repository, @Service ecc...) e @Autowired. Per abilitare tutto ciò ho inserito nel mio file xml questo: Codice PHP:
Successivamente son andato a creare il mio bel HibernateDAO, subito pensavo di usare l'HibernateDaoSupport+getHibernateTemplate(), ma poi ho letto che questo è un modo vecchio di operare, con le Hibernate API 3 e Spring 3.* basta la sessionFactory, spero di aver capito bene io... Dunque questo è un Dao di esempio: Codice PHP:
EDIT: risolto, creavo il DAO semplicemente con new PersonHDAO(), invece andava preso dal context con context.getBean(PersonHDAO.class). Ok ora sessionFactory non è più NULL. Ho però un altro problema ora, quando faccio context.getBean(PersonHDAO.class), mi lancia questa eccezione: Codice:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [data.PersonHDAO] is defined: expected single bean but found 0: [/code] Grazie ancora. Ultima modifica di MEMon : 08-11-2010 alle 23:09. |
![]() |
![]() |
![]() |
#18 |
Senior Member
Iscritto dal: Dec 2002
Messaggi: 3359
|
Risolto anche l'ultima, adesso non so perché ma sembra che il transaction manager non mi gestisca in automatico le transazioni.
Infilo qui tutto il file xml così magari se qualcuno vede delle inesattezze me le può riferire: Codice PHP:
Codice PHP:
Codice:
//file TestController.java public interface TestController { public List<Test> findAll(); } //file TestControllerImp.java @Controller public class TestControllerImp implements TestController{ @Autowired private SessionFactory sessionFactory; /** * @return the sessionFactory */ public SessionFactory getSessionFactory() { return sessionFactory; } /** * @param sessionFactory the sessionFactory to set */ public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory=sessionFactory; } @Transactional public List<Test> findAll() { return sessionFactory.getCurrentSession().createQuery("from Test").list(); } } //nel main TestController tc=context.getBean(TestController.class); List<Test> list=tc.findAll(); org.hibernate.HibernateException: createQuery is not valid without active transaction ed è quindi palese che il transaction manager non mi fa partire una transazione alla chiamata del metodo findAll, come invece speravo. Dove sbaglio? |
![]() |
![]() |
![]() |
#19 |
Senior Member
Iscritto dal: Dec 2002
Messaggi: 3359
|
Codice:
<prop key="hibernate.current_session_context_class">thread</prop> <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop> ![]() |
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 16:51.