2013-03-08 72 views
29

我在Spring世界很新,我開發了一個使用Spring 3.2.1和Hibernate 4.1.9實現DAO的簡單項目。該項目正常工作,但我對使用此DAO的CRUD方法的Spring註釋使用@Transactional表示懷疑。關於Spring @Transactional註解的一些說明方法

這是實現我的項目的CRUD操作的類的全部代碼:

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(); 
     } 

    } 

} 

好吧,你可以看到一些方法使用@Transactional註解annoted。

我在這裏http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html有關使用此批註的方法看書的官方文檔,它看到:使用@事務必須有事務語義,但它與事務語義意味着的方法annoted?

這意味着methos執行必須被視爲執行事務嗎?因此,這意味着方法操作必須被視爲可能導致成功或失敗的單一操作,如果成功,操作的結果必須是永久性的,而如果失敗返回到之前的狀態交易的開始。

這是使用的含義@Transactional註解的方法?

什麼恰恰意味着在addPerson的()方法的@Transactional註解的readOnly的= FALSE屬性?這意味着我也可以在數據庫中寫入記錄(而不僅僅是讀取它)或什麼?這個疑問是相關的,因爲我明白,默認情況下,使用@Transactional註釋定義的交易是讀取/寫入而不只是讀取... 我也嘗試刪除(readOnly = false)屬性和仍然工作正常(在數據庫表中插入新記錄)

以下dout是:「爲什麼某些方法使用@Transactional註釋和其他一些方法進行註釋?是否使用@ @來標記所有CRUD方法是一個很好的實踐,交易?」

TNX

安德烈

+0

我猜你的交易配置無效,因爲你可以插入一些只讀事務。我的猜測是,你根本不使用交易。請詳細介紹一下您如何配置交易環境(appcontext)。 也不要在DAO級別聲明您的事務,而是在業務級別(您實際使用DAO的地方)聲明您的事務。 – 2013-03-08 18:20:49

回答

51

首先,你不應該讓DAO方法事務性的,但服務的方法。其次,使用Transactional是一種讓Spring爲你啓動和提交/回滾事務的方法。所以你不應該自己開始和提交交易。

第三:只有當您使用知道如何將Hibernate會話與事務關聯的事務管理器(通常是HibernateTransactionManager)時,這纔會起作用。會話工廠也應該由Spring處理,並在Spring中注入到DAO中。 DAO的代碼應該如下所示:

第四:您不應該打開新會話,而是獲取當前與Spring關聯的當前事務。

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); 
    } 
} 

閱讀the documentation瞭解更多信息。

+1

好吧......現在我有更多的疑問比之前發佈我的問題:-) 1)你是什麼意思,我不應該使DAO方法事務性,但服務方法?我找到了很多使用@Transaction註釋來標註DAO方法的例子。2)爲什麼你從發佈在你的答案中的方法中刪除這個註釋 3)在這裏閱讀:http://www.tutorialspoint.com/ hibernate/hibernate_sessions.htm它說:「會話對象是輕量級的,每次需要與數據庫進行交互時都要實例化」 – AndreaNobili 2013-03-08 18:45:11

+0

還有:「會話對象不應該長時間保持打開狀態,因爲它們是通常不是線程安全的,應該根據需要創建並銷燬它們。「所以你說我這是好的實踐只打開一次會議,然後獲得目前的公開會議? – AndreaNobili 2013-03-08 18:45:55

+9

我不是那麼說。我在說,你應該得到Spring的當前事務關聯的會話,並且在交易結束時Spring也會關閉這個會話。它是Spring,每次打開/關閉事務時都會打開和關閉會話。我的意思是服務與DAO方法是一個服務通常會調用多個DAO方法,並且所有這些調用都應該是同一個事務的一部分(例如:減少一個帳戶的餘額,增加另一個帳戶的餘額,創建一個傳遞對象,在審計表中創建aline – 2013-03-08 19:17:15