2013-03-08 15 views
29

Sono abbastanza nuovo nel mondo Spring e ho sviluppato un progetto semplice che utilizza Spring 3.2.1 e Hibernate 4.1.9 per implementare un DAO. Il progetto funziona correttamente ma ho qualche dubbio sull'uso di @Transactional annotazione Spring sul metodo CRUD di questo DAO.Alcuni chiarimenti sull'annotazione Spring @Transactional su un metodo

Questo è l'intero codice della classe che implementa l'operazione CRUD del mio progetto:

package org.andrea.myexample.HibernateOnSpring.dao; 

import java.util.List; 

import org.andrea.myexample.HibernateOnSpring.entity.Person; 

import org.hibernate.Criteria; 
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction; 
import org.hibernate.SessionFactory; 
import org.hibernate.cfg.Configuration; 
import org.hibernate.service.ServiceRegistry; 
import org.hibernate.service.ServiceRegistryBuilder; 
import org.springframework.transaction.annotation.Transactional; 

public class PersonDAOImpl implements PersonDAO { 

    // Factory per la creazione delle sessioni di Hibernate: 
    private static SessionFactory sessionFactory; 

    // Metodo Setter per l'iniezione della dipendenza della SessionFactory: 
    public void setSessionFactory(SessionFactory sessionFactory) { 
     this.sessionFactory = sessionFactory; 
    } 

    /** CREATE CRUD Operation: 
    * Aggiunge un nuovo record rappresentato nella tabella rappresentato 
    * da un oggetto Person 
    */ 
    @Transactional(readOnly = false) 
    public Integer addPerson(Person p) { 

     System.out.println("Inside addPerson()"); 

     Session session = sessionFactory.openSession(); 

     Transaction tx = null; 
     Integer personID = null; 

     try { 
      tx = session.beginTransaction(); 

      personID = (Integer) session.save(p); 
      tx.commit(); 
     } catch (HibernateException e) { 
      if (tx != null) 
       tx.rollback(); 
      e.printStackTrace(); 
     } finally { 
      session.close(); 
     } 

     return personID; 

    } 

    // READ CRUD Operation (legge un singolo record avente uno specifico id): 
    public Person getById(int id) { 

     System.out.println("Inside getById()"); 

     Session session = sessionFactory.openSession(); 

     Transaction tx = null;   
     Person retrievedPerson = null; 

     try { 
      tx = session.beginTransaction(); 
      retrievedPerson = (Person) session.get(Person.class, id); 
      tx.commit(); 
     }catch (HibernateException e) { 
      if (tx != null)     
       tx.rollback();   
      e.printStackTrace(); 
     } finally {     
      session.close(); 
     } 

     return retrievedPerson; 
    } 

    // READ CRUD Operation (recupera la lista di tutti i record nella tabella): 
    @SuppressWarnings("unchecked") 
    public List<Person> getPersonsList() { 

     System.out.println("Inside getPersonsList()"); 

     Session session = sessionFactory.openSession(); 
     Transaction tx = null; 
     List<Person> personList = null; 

     try { 
      tx = session.beginTransaction(); 
      Criteria criteria = session.createCriteria(Person.class); 
      personList = criteria.list(); 
      System.out.println("personList: " + personList); 
      tx.commit(); 
     }catch (HibernateException e) { 
      if (tx != null)     
       tx.rollback();   
      e.printStackTrace(); 
     } finally { 
      session.close(); 
     } 
     return personList; 
    } 

    // DELETE CRUD Operation (elimina un singolo record avente uno specifico id): 
    public void delete(int id) { 

     System.out.println("Inside delete()"); 

     Session session = sessionFactory.openSession(); 
     Transaction tx = null; 

     try { 
      tx = session.beginTransaction(); 
      Person personToDelete = getById(id); 
      session.delete(personToDelete); 
      tx.commit(); 
     }catch (HibernateException e) { 
      if (tx != null)     
       tx.rollback();   
      e.printStackTrace(); 
     } finally { 
      session.close(); 
     } 

    } 

    @Transactional 
    public void update(Person personToUpdate) { 

     System.out.println("Inside update()"); 

     Session session = sessionFactory.openSession(); 
     Transaction tx = null; 

     try { 
      System.out.println("Insite update() method try"); 
      tx = session.beginTransaction(); 
      session.update(personToUpdate); 

      tx.commit(); 
     }catch (HibernateException e) { 
      if (tx != null)     
       tx.rollback();   
      e.printStackTrace(); 
     } finally { 
      session.close(); 
     } 

    } 

} 

Ok, come si può vedere alcuni metodi sono annotata con annotazioni @Transactional.

sto readin la documentazione ufficiale qui http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html circa l'uso di questa annotazione sui metodi e vedere che: Metodo annotata utilizzando @Transactional deve avere semantica transazionale ma cosa vuol dire con semantica transazionale?

Significa che l'esecuzione del methos deve essere considerata come l'esecuzione di una transazione? Quindi significa che le operazioni del metodo devono essere considerate come una singola operazione che può portare a un successo o un fallimento, in caso di successo, i risultati delle operazioni devono essere permanenti, mentre in caso di mancato ritorno allo stato precedente l'inizio della transazione.

È questo il significato dell'uso annotazione @Transactional su un metodo?

E che cosa significa esattamente il readOnly = false attributo nella annotazioni @Transactional del addPerson() metodo? significa che posso anche scrivere un record nel database (e non solo leggerlo) o cosa? Il dubbio è correlato perché ho capito che, per impostazione predefinita, una transazione definita utilizzando @Transactional annotaion è lettura/scrittura e non solo lettura ... Ho anche provato a eliminare l'attributo (readOnly = false) e funziona ancora bene (inserisci il nuovo record nella tabella del database)

Il seguente dout è: "perché alcuni metodi vengono annotati usando l'annotazione @Transactional e altri metodi no? è un buon metodo per annotare il metodo ALL CRUD con @ Transazionale?"

Tnx

Andrea

+0

Immagino che la configurazione della transazione non sia valida, dal momento che è possibile inserire qualcosa con una transazione di sola lettura. La mia ipotesi è che tu non usi affatto le transazioni. Vi preghiamo di fornirci ulteriori dettagli su come avete configurato il vostro ambiente di transazione (appcontext). Inoltre, non dichiarare le transazioni a livello di DAO, ma a livello aziendale (lì dove effettivamente si utilizzano i DAO). –

risposta

51

Prima di tutto, non si dovrebbe fare DAO metodi transazionale, ma i metodi di servizio.

In secondo luogo, l'utilizzo di Transactional è un metodo che consente di avviare le transazioni Spring start e commit/rollback. Quindi non dovresti iniziare e commettere transazioni da solo.

Terzo: funziona solo se si utilizza un gestore transazioni che sa come associare una sessione di sospensione alla transazione (in genere, un HibernateTransactionManager). La factory di sessione dovrebbe anche essere gestita da Spring e iniettata da Spring nei tuoi DAO. Il codice del DAO dovrebbe apparire così:

In quarto luogo: non si dovrebbe aprire una nuova sessione, ma ottenere quella attuale, associata alla transazione corrente per primavera.

public class PersonDAOImpl implements PersonDAO { 

    @Autowired 
    private SessionFactory sessionFactory; 

    public Integer addPerson(Person p) { 
     Session session = sessionFactory.getCurrentSession(); 
     Integer personID = (Integer) session.save(p); 
     return personID; 
    } 

    public Person getById(int id) { 
     Session session = sessionFactory.getCurrentSession(); 
     Person retrievedPerson = (Person) session.get(Person.class, id); 
     return retrievedPerson; 
    } 

    @SuppressWarnings("unchecked") 
    public List<Person> getPersonsList() { 
     Session session = sessionFactory.getCurrentSession(); 
     Criteria criteria = session.createCriteria(Person.class); 
     return criteria.list(); 
    } 

    public void delete(int id) { 
     Session session = sessionFactory.getCurrentSession(); 
     Person personToDelete = getById(id); 
     session.delete(personToDelete); 
    } 

    public void update(Person personToUpdate) { 
     Session session = sessionFactory.getCurrentSession(); 
     session.update(personToUpdate); 
    } 
} 

Leggi the documentation per ulteriori informazioni.

+1

Ok ... ora ho più dubbi di prima posta la mia domanda :-) 1) Cosa vuoi dire che non dovrei rendere transazionale i metodi DAO, ma i metodi di servizio? Ho trovato molti esempi in cui il metodo DAO è annotato usando l'annotazione @Transaction 2) Perché hai eliminato questa annotazione dal metodo pubblicato nella risposta 3) Leggere qui: http://www.tutorialspoint.com/ hibernate/hibernate_sessions.htm dice che: "l'oggetto Session è leggero e progettato per essere istanziato ogni volta che è necessaria un'interazione con il database" – AndreaNobili

+0

e anche: "Gli oggetti di sessione non devono essere mantenuti aperti per un lungo periodo perché sono di solito non sono thread safe e dovrebbero essere creati e distrutti come necessario. " Quindi, cosa mi dici che è una buona pratica aprire la sessione solo una volta e poi ottenere la sessione aperta corrente? – AndreaNobili

+9

Non sto dicendo questo. Sto dicendo che dovresti ottenere la sessione che è stata associata alla transazione corrente in primavera, e che sarà chiusa anche da Spring alla fine della transazione. È Spring che aprirà e chiuderà una sessione ogni volta che una transazione viene aperta/chiusa. Quello che intendo con i metodi service vs DAO è che un servizio chiamerà in genere diversi metodi DAO e tutte queste chiamate dovrebbero far parte della stessa trnsaction (ad esempio: decrementare il saldo di un account, incrementare il saldo di un altro account, creare un trasferire oggetto, creare aline in una tabella di controllo: –

Problemi correlati