java中Hibernate session在service實現事務getCurrentSession()和openSession()區別

來源:互聯網
上載者:User

當我們在使用Hibernate作為資料庫操作的類庫時,我們一般在DAO層裡與資料庫相關的操作,把商務邏輯寫在service層裡。但是如果我們的項目比較小,那麼直接在dao層裡寫事務也是可以的,這個就是看個人了,沒有什麼特別的規定。但是如果項目比較大,那麼DAO應該只做單純的資料庫的操作,service寫事務的操作,即整個商務邏輯。

例如:商務邏輯要求向資料庫中的使用者表增加一個使用者,同時向日誌表中加入一條日誌,而這需要調用DAO的兩個方法(UserDao的saveUser和LogDao的saveLog)。這顯然是一個事務,也就是如果一個操作出現了問題,就要復原到初始的狀態。那麼如何在Service層控制事務呢,本文就以此例的代碼說明。

在DAO進行Session事務出現的問題

我們先看看在DAO層裡寫Hibernate的session的事務。

package com.xxg;
 
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
public class HibernateUtil {
 
    private static final SessionFactory sessionFactory = buildSessionFactory();
    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

建立使用者表T_user(id,username)和日誌表T_log(id,content),以及它們對應的實體類User、Log及對應檔,這裡就不一一貼出代碼。


public class UserDao {
 
    public void saveUser(User user){
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //擷取SessionFactory
        Session session = sessionFactory.openSession();// openSession
        session.beginTransaction(); //開始事務
 
        session.save(user);
 
        session.getTransaction().commit(); //事務提交
        session.close(); //關閉session
    }
}


public class LogDao {
 
    public void saveLog(Log log){
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //擷取SessionFactory
        Session session = sessionFactory.openSession();// openSession
        session.beginTransaction(); //開始事務
 
        session.save(log);
 
        session.getTransaction().commit(); //事務提交
        session.close(); //關閉session
    }
 
}

接下來我們看看在service中寫一個商務邏輯

public class TestService {
 
    public void save(User user){
        UserDao userDao = new UserDao();
        userDao.saveUser(user);
 
        LogDao logDao = new LogDao();
        Log log = new Log();
        log.setContent("插入一個使用者");
        logDao.saveLog(log);
    }
 
}
可以看到,我們在兩個DAO裡寫了資料庫的事務,代碼中高亮顯示了,session.beginTransaction()顯示聲明事務的開始。

這樣寫是不對的,因為這兩個事情作為一個事務來進行的,會出現一個事務成功提交,而另外一個可能提交失敗,導致不一致的情況,這樣這兩個操作不算是一個事務transaction,所以這麼寫就是一個失敗的交易。

因此,我們要將事務在service中進行聲明。

在service層寫session的資料庫事務

為了將事務放在service中,我們需要更改HibernateUtil的代碼才能實現。否則使用上面的那個不能達到我們的需求。在這個新的HibernateUtil代碼中,利用了ThreadLocal的線程內的局部變數來儲存hibernate的session對象。這樣就可以在不同的class中使用同一個session對象,而不用傳遞參數。

public class HibernateUtil {
    public static final ThreadLocal session = new ThreadLocal();
 
    public static final SessionFactory sessionFactory;
    static {
        try {
            sessionFactory = new Configuration().configure().buildSessionFactory();
        } catch ( Throwable ex ) {
            throw new ExceptionInInitializerError( ex );
        }
    }
 
    public static Session currentSession() throws HibernateException
    {
        Session s = session.get();
        if ( s == null )
        {
            s = sessionFactory.openSession();
            session.set( s );
        }
        return(s);
    }
 
    public static void closeSession() throws HibernateException
    {
        Session s = session.get();
        if ( s != null )
        {
            s.close();
        }
        session.set( null );
    }
}

接下來,我們將事務放在service中。看代碼:


public class TestService {
 
    public void save(User user){
 
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //擷取SessionFactory
        Session session = sessionFactory.getCurrentSession();//getCurrentSession
        session.beginTransaction();//事務開始
 
        UserDao userDao = new UserDao();
        userDao.saveUser(user);
 
        LogDao logDao = new LogDao();
        Log log = new Log();
        log.setContent("插入一個使用者");
        logDao.saveLog(log);
        session.getTransaction().commit();//事務提交
    }
 
}


public class LogDao {
 
    public void saveLog(Log log) throws RuntimeException{
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //擷取SessionFactory
        Session session = sessionFactory.getCurrentSession(); //getCurrentSession
 
        session.save(log);
 
        throw new RuntimeException();
    }
}


public class UserDao {
 
    public void saveUser(User user){
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //擷取SessionFactory
        Session session = sessionFactory.getCurrentSession();//getCurrentSession
 
        session.save(user);
 
    }
 
}

通過getCurrentSession()可以獲得當前線程的session對象,通過它來進行共用session。這樣事務就從service開始,然後再service結束。

getCurrentSession()與openSession()區別

getCurrentSession建立的session會和綁定到當前線程,而openSession不會。

getCurrentSession建立的線程會在交易回復或事物提交後自動關閉,而openSession必須手動關閉

採用getCurrentSession()建立的session會綁定到當前線程中,而採用openSession()
建立的session則不會
* 採用getCurrentSession()建立的session在commit或rollback時會自動關閉,而採用openSession()
建立的session必須手動關閉

2、使用getCurrentSession()需要在hibernate.cfg.xml檔案中加入如下配置:

* 如果使用的是本地事務(jdbc事務)
<property name=”hibernate.current_session_context_class”>thread</property>
* 如果使用的是全域事務(jta事務)
<property name=”hibernate.current_session_context_class”>jta</property>

getCurrentSession()與openSession()關聯

在 SessionFactory 啟動的時候, Hibernate 會根據配置建立相應的 CurrentSessionContext ,在 getCurrentSession() 被調用的時候,實際被執行的方法是 CurrentSessionContext.currentSession() 。在 currentSession() 執行時,如果當前 Session 為空白, currentSession 會調用 SessionFactory 的 openSession 。所以 getCurrentSession() 對於 Java EE 來說是更好的擷取 Session 的方法。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.