歡迎光臨
每天分享高質量文章

通向架構師的道路(第七天)之漫談使用 ThreadLocal 改進你的層次的劃分 ( 下 )

(點選上方公眾號,可快速關註)


來源:袁鳴凱 ,

blog.csdn.net/lifetragedy/article/details/7751059

2.6.8 ClassRoomDAOImpl類

package sky.org.dao.impl;

  

import java.sql.*;

import java.util.*;

import sky.org.dao.ClassRoomDAO;

import sky.org.util.db.ConnectionManager;

 

public class ClassRoomDAOImpl implements ClassRoomDAO {

 

         public void addStudentClassRoom(String roomId, String sNo) throws Exception {

 

                   Connection conn = null;

 

                   PreparedStatement pstmt = null;

 

                   try {

 

                            conn = ConnectionManager.getConnection();

 

                            pstmt = conn

 

                                               .prepareStatement(ClassRoomDAOSql.ADD_STUDENT_CLASSROOM);

 

                            pstmt.setString(1, roomId);

 

                            pstmt.setString(2, sNo);

 

                            pstmt.executeUpdate();

 

                   } catch (Exception e) {

 

                            throw new Exception(“addStudentClassRoom:” + e.getMessage(), e);

 

                   } finally {

 

                            try {

 

                                     if (pstmt != null) {

 

                                               pstmt.close();

 

                                               pstmt = null;

 

                                     }

 

                            } catch (Exception e) {

 

                            }

 

                   }

 

         }

 

}

2.6.9 StudentDAO介面

package sky.org.dao;

 

import java.util.*;

 

import sky.org.bean.Student;

 

public interface StudentDAO {

 

         public void addStudent(Student std) throws Exception;

 

}

2.6.10 StudentDAOImpl類

package sky.org.dao.impl;

 

  

 

import java.sql.*;

 

import javax.sql.*;

 

  

 

import org.apache.commons.logging.Log;

 

import org.apache.commons.logging.LogFactory;

 

  

 

import sky.org.bean.Student;

 

import sky.org.dao.StudentDAO;

 

import sky.org.util.db.ConnectionManager;

 

  

 

import java.util.List;

 

import java.util.ArrayList;

 

import java.util.Vector;

 

import java.text.*;

 

import sky.org.util.StringUtil;

 

  

 

public class StudentDAOImpl implements StudentDAO {

 

         private Log logger = LogFactory.getLog(this.getClass());

 

  

 

         public void addStudent(Student std) throws Exception {

 

                   Connection conn = null;

 

                   PreparedStatement pstmt = null;

 

                   try {

 

                            conn = ConnectionManager.getConnection();

 

                            pstmt = conn.prepareStatement(StudentDAOSql.ADD_STUDENT);

 

                            pstmt.setString(1, std.getsNo());

 

                            pstmt.setString(2, std.getsName());

 

                            pstmt.setString(3, std.getsAge());

 

                            pstmt.setString(4, std.getGender());

 

                            pstmt.setDate(5, StringUtil.convertStrToDate(std.getSbirth()));

 

  

 

                            pstmt.executeUpdate();

 

                   } catch (Exception e) {

 

                            throw new Exception(“addStudent:” + e.getMessage(), e);

 

                   } finally {

 

                            try {

 

                                     if (pstmt != null) {

 

                                               pstmt.close();

 

                                               pstmt = null;

 

                                     }

 

                            } catch (Exception e) {

 

                            }

                   }

         }

 

  

 

         public void delStudent(String sNo) throws Exception {

 

                   Connection conn = null;

 

                   PreparedStatement pstmt = null;

 

                   try {

 

                            conn = ConnectionManager.getConnection();

 

                            pstmt = conn.prepareStatement(StudentDAOSql.DEL_STUDENT);

 

                            pstmt.setString(1, sNo);

 

                            pstmt.executeUpdate();

 

                   } catch (Exception e) {

 

                            throw new Exception(“delStudent:” + e.getMessage(), e);

 

                   } finally {

 

                            try {

 

                                     if (pstmt != null) {

 

                                               pstmt.close();

 

                                               pstmt = null;

 

                                     }

 

                            } catch (Exception e) {

 

                            }

 

                   }

 

         }

 

}

2.6.11 StudentDAOSql類

package sky.org.dao.impl;

 

public class StudentDAOSql {

 

public final static String ADD_STUDENT = “insert into t_student(sno, sname, sage, gender,

 

sbirth)values(?,?,?,?,?)”;

 

}

2.6.12 ClassRoomDAOSql類

package sky.org.dao.impl;

 

public class ClassRoomDAOSql {

 

         public static String ADD_STUDENT_CLASSROOM = “insert into

t_student_classroom(room_id,sno)values(?,?)”;

 

}

2.6.13 ClassRoom 類

package sky.org.bean;

 

import java.io.*;

 

 

public class ClassRoom implements Serializable {

 

         private String roomId = “”;

         private String roomName = “”;

 

  

         public String getRoomId() {

                   return roomId;

 

         }

 

         public void setRoomId(String roomId) {

 

                   this.roomId = roomId;

 

         }

 

         public String getRoomName() {

                   return roomName;

 

         }

 

         public void setRoomName(String roomName) {

                   this.roomName = roomName;

 

         }

 

}

2.6.14 Student類

package sky.org.bean;

import java.io.*;

 

public class Student implements Serializable {

 

         public String getsNo() {

                   return sNo;

         }

 

         public void setsNo(String sNo) {

 

                   this.sNo = sNo;

 

         }

 

 

         public String getsName() {

                   return sName;

         }

 

         public void setsName(String sName) {

 

                   this.sName = sName;

         }

 

         public String getsAge() {

                   return sAge;

         }

 

  

 

         public void setsAge(String sAge) {

 

                   this.sAge = sAge;

 

         }

 

  

 

         public String getGender() {

                   return gender;

         }

 

         public void setGender(String gender) {

                   this.gender = gender;

         }

 

 

         private String sNo = “”;

         private String sName = “”;

         private String sAge = “”;

         private String gender = “”;

         private String sbirth = “”;

         private String classRoomId = “”;

         private String classRoomName = “”;

 

 

         public String getClassRoomId() {

 

                   return classRoomId;

 

         }

 

         public void setClassRoomId(String classRoomId) {

 

                   this.classRoomId = classRoomId;

         }

 

         public String getClassRoomName() {

                   return classRoomName;

 

         }

 

  

 

        public void setClassRoomName(String classRoomName) {

                   this.classRoomName = classRoomName;

 

         }

 

 

         public String getSbirth() {

 

                   return sbirth;

 

         }

 

 

         public void setSbirth(String sbirth) {

                   this.sbirth = sbirth;

         }

}

2.6.15 StudentCRUD類(執行主類)

package sky.org.test;

 

import sky.org.bean.Student;

 

import sky.org.service.StudentService;

 

import sky.org.service.impl.StudentServiceImpl;

 

public class StudentCRUD {

 

         public void addStudent() throws Exception {

 

                   StudentService stdService = new StudentServiceImpl();

 

                   Student std = new Student();

 

                   std.setsNo(“101”);

 

                   std.setsName(“abc”);

 

                   std.setSbirth(“1977/01/01”);

 

                   std.setsAge(“35”);

 

                   std.setGender(“m”);

 

                   std.setClassRoomId(“1”);

 

                   std.setClassRoomName(“class1”);

 

                   stdService.addStudent(std);

 

         }

 

  

 

         public static void main(String[] args) {

 

                   StudentCRUD testStudentCRUD = new StudentCRUD();

 

                   try {

 

                            testStudentCRUD.addStudent();

 

                   } catch (Exception e) {

 

                            e.printStackTrace();

 

                            System.exit(-1);

 

                   }

 

         }

 

}

三、Hibernate裡的ThreadLocal

Hibernate在事務操作中也支援ThreadLocal的作法,我們這邊指的是不用Spring去做代理,而直接用Hibernate。即:

Service Method{

 

hbDAO1.doSomething();

 

hbDAO2.doSomething();

 

hbDAO3.doSomething();

 

。。。

 

}

Hibernate版本3後增加了新特性,即getCurrentSession()。

3.1 getCurrentSession與openSession的區別

3.1.1 openSession

我們傳統的做法是openSession即:

public void testUser() throws Exception {

 

                   Transaction tran = null;

 

                   SessionFactory factory = null;

 

                   UserDAO userDAO = new UserDAOImpl();

 

                   try {

 

                            factory = HibernateUtil.getInstance().getSessionFactory();

 

                            Session session = factory.openSession();

 

                            tran = session.beginTransaction();

 

                            TUser testUser = new TUser();

 

                        testUser.setId(new Integer(i));

 

                            testUser.setName(“abc”);

 

                            userDAO.addUser(testUser);

 

                            tran.commit();

 

                   } catch (Exception e) {

 

                            tran.rollback();

 

                            throw new Exception(e);

 

                   } finally {

 

                            try{

 

    if(session!=null){

 

    session.close();

    session=null();

 

}

 

}catch(Excepton e){}

 

                   }

         }

這樣做,能夠保證我們每次在finally塊中正確關閉session,但是,如果我們也遇上了這樣的case即:

Service Method{

 

hbDAO1.doSomething();

 

hbDAO2.doSomething();

 

hbDAO3.doSomething();

 

。。。

 

}

這時,我們如果用的是openSession,應該怎麼辦?

解決方案一:

自己用ThreadLocal樣式寫一個SessionManagement類,來維護這個session。

解決方案二:

把在Service方法中開啟的session,傳到每個dao方法中,使每個dao方法使用同一個session,最後在Service方法中去關閉它(很爛的做法)。

下麵我們來看看Hibernate自身提供的getCurrentSession()的做法吧

3.1.2 getCurrentSession

要使用這個getCurrentSession,你的hibernate的設定必須如下(紅色加粗部分顯示-就喜歡粗J):

 

/span>

 

          “-//Hibernate/Hibernate Configuration DTD 3.0//EN”

 

          “http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd”>

 

 

         

 

                   

 

                            jdbc:oracle:thin:@localhost:1521:myorcl

 

                   

 

                   

 

                            org.hibernate.dialect.Oracle9Dialect

 

                   

 

                   abc

 

                   abc

 

                   

 

                            oracle.jdbc.OracleDriver

 

                   

 

                   true

 

                   update

 

                   thread

 

                   

 

         

 

然後上述程式碼將變成如下的樣子:

public void testUser() throws Exception {

 

                   Transaction tran = null;

 

                   SessionFactory factory = null;

 

                   UserDAO userDAO = new UserDAOImpl();

 

                   try {

 

                            factory = HibernateUtil.getInstance().getSessionFactory();

 

                            Session session = factory.getCurrentSession();

 

                            tran = session.beginTransaction();

 

                            for (int i = 0; i < 100; i++) {

 

                                     TUser testUser = new TUser();

 

                                     testUser.setId(new Integer(i));

 

                                     testUser.setName(“abc”);

 

                                     userDAO.addUser(testUser);

 

                            }

 

                            tran.commit();

 

                   } catch (Exception e) {

 

                            tran.rollback();

 

                            throw new Exception(e);

 

                   } finally {

 

                            ThreadLocalSessionContext.unbind(factory);

 

                   }

 

         }

而你的每個DAO方法中的程式碼是這樣實現的:

public void addUser(TUser user) throws Exception {

 

         SessionFactory factory = HibernateUtil.getInstance()

 

                            .getSessionFactory();

 

         Session session = factory.getCurrentSession();

 

         session.save(user);

 

}

是不是很方便的哈。

3.1.3 openSession與getCurrentSession的區別

嚴重註意下麵幾點:

  • openSession一旦被呼叫,必須且一定要在finally塊中close,要不然你就等著out of memory吧;

  • 如果你使用的是getCurrentSession,那麼你不能在finally塊中呼叫”session.close()”,不行你可以在finally塊中用try-catch把session.close();包起來,然後在catch{}塊中丟擲這個exception,這個exception將會是:sessionhas been already closed。

因為:

l   如果你用的是getCurrentSession,那麼它在session.commit()或者是session.rollback()時就已經呼叫了一次session.close()了,因此你只要正確放置session.commit()與rollback()即可。

l   你必須在finally塊中呼叫”ThreadLocalSessionContext.unbind(factory);”,以使得當前的事務結束時把session(即dbconnection)還回db connection pool中

如果你使用的是getCurrentSession,那麼就算你是一個簡單的select陳述句,也必須包含在:

tran = session.beginTransaction();

 

//your select hibernate query

 

tran.commit();

這樣的事務塊中,要不然它將會丟擲這樣的一個錯誤:

NoHibernate Session bound to thread, and configuration does not allow creation ofnon-transactional

看下麵的例子:

try {

 

                    factory = HibernateUtil.getInstance().getSessionFactory();

 

                    Session session = factory.getCurrentSession();

 

                    tran = session.beginTransaction();

 

                    TUser testUser = userDAO.getUserByID(“1”);

 

                    log.info(“user id====”+testUser.getId()+”  user name====”+testUser.getName());

 

                    tran.commit();

 

           } catch (Exception e) {

 

                    tran.rollback();

 

                    throw new Exception(e);

 

           } finally {

 

                    ThreadLocalSessionContext.unbind(factory);

 

                   }

可以看到我們的查詢是被tran=session.beginTransaction一直到tran.commit()或者是tran.rollback()結束的,如果,你把你的hibernate查詢移到了tran=session.beginTransaction的上面。。。就會拋上述這個錯誤。

3.1.4 getCurrentSession帶來的問題

getCurrentSession非常好,不需要我們自己寫ThreadLocal只需要在hibernate.cfg的配置檔案中聲音一下就可以獲得ThreadLocal的好處,便於我們劃分我們的程式的層次與封裝,帶也帶來了一定的效能問題。

特別是“如果你使用的是getCurrentSession,那麼就算你是一個簡單的select陳述句,也必須包含在事務塊中”。這給我們帶來了很大的問題。

因此,本人建議,在碰到如果:

  1. 一個service方法中只有單個dao操作且此操作是一個select類的操作,請使用openSession,並且即時在finally塊中關閉它;

  2. 如果一個service方法中涉及到多個dao操作,請一定使用getCurrentSession;

  3. 如果一個service方法中混合著select操作,delete, update, insert操作。請按照下述原則:

  4. 將屬於select的操作,單獨做成一個dao方法,該dao使用openSession並且在finally塊中及時關閉session,該dao只需要傳回一個java的object如:List即可,如果出錯將exception拋回給呼叫它的service方法。

  5. 對於其它的delete, insert, update的dao操作,請使用getCurrentSession。

  6. 忌諱,把select類的操作放在“事務”中。

系列


看完本文有收穫?請轉發分享給更多人

關註「ImportNew」,提升Java技能

贊(0)

分享創造快樂