久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

通向架構(gòu)師的道路(第七天)之漫談使用ThreadLocal改進(jìn)你的層次的劃分

 richsky 2012-07-17

通向架構(gòu)師的道路(第七天)之漫談使用ThreadLocal改進(jìn)你的層次的劃分

分類: 架構(gòu)師之路 268人閱讀 評(píng)論(1) 收藏 舉報(bào)

一,、什么是ThreadLocal

早在JDK 1.2的版本中就提供java.lang.ThreadLocal,,ThreadLocal為解決多線程程序的并發(fā)問(wèn)題提供了一種新的思路。使用這個(gè)工具類可以很簡(jiǎn)潔地編寫出優(yōu)美的多線程程序,。

ThreadLocal很容易讓人望文生義,,想當(dāng)然地認(rèn)為是一個(gè)“本地線程”。其實(shí),,ThreadLocal并不是一個(gè)Thread,,而是Thread的局部變量,也許把它命名為ThreadLocalVariable更容易讓人理解一些,。

當(dāng)使用ThreadLocal維護(hù)變量時(shí),,ThreadLocal為每個(gè)使用該變量的線程提供獨(dú)立的變量副本,,所以每一個(gè)線程都可以獨(dú)立地改變自己的副本,而不會(huì)影響其它線程所對(duì)應(yīng)的副本,。

從線程的角度看,,目標(biāo)變量就象是線程的本地變量,這也是類名中“Local”所要表達(dá)的意思,。

線程局部變量并不是Java的新發(fā)明,,很多語(yǔ)言(如IBM IBM XL FORTRAN)在語(yǔ)法層面就提供線程局部變量。在Java中沒(méi)有提供在語(yǔ)言級(jí)支持,,而是變相地通過(guò)ThreadLocal的類提供支持,。

所以,在Java中編寫線程局部變量的代碼相對(duì)來(lái)說(shuō)要笨拙一些,,因此造成線程局部變量沒(méi)有在Java開發(fā)者中得到很好的普及,。

ThreadLocal的接口方法

ThreadLocal類接口很簡(jiǎn)單,只有4個(gè)方法,,我們先來(lái)了解一下:

void set(Object value)

設(shè)置當(dāng)前線程的線程局部變量的值,。

public Object get()

該方法返回當(dāng)前線程所對(duì)應(yīng)的線程局部變量。

public void remove()

將當(dāng)前線程局部變量的值刪除,,目的是為了減少內(nèi)存的占用,,該方法是JDK 5.0新增的方法。需要指出的是,,當(dāng)線程結(jié)束后,,對(duì)應(yīng)該線程的局部變量將自動(dòng)被垃圾回收,,所以顯式調(diào)用該方法清除線程的局部變量并不是必須的操作,,但它可以加快內(nèi)存回收的速度。

protected ObjectinitialValue()

返回該線程局部變量的初始值,,該方法是一個(gè)protected的方法,,顯然是為了讓子類覆蓋而設(shè)計(jì)的。這個(gè)方法是一個(gè)延遲調(diào)用方法,,在線程第1次調(diào)用get()或set(Object)時(shí)才執(zhí)行,,并且僅執(zhí)行1次。ThreadLocal中的缺省實(shí)現(xiàn)直接返回一個(gè)null,。

值得一提的是,,在JDK5.0中,ThreadLocal已經(jīng)支持泛型,,該類的類名已經(jīng)變?yōu)門hreadLocal<T>,。API方法也相應(yīng)進(jìn)行了調(diào)整,新版本的API方法分別是void set(T value),、T get()以及T initialValue(),。

一,、來(lái)看一個(gè)實(shí)際案例

2.1 同一Service方法中調(diào)用多個(gè)Dao方法

可以看到,我們有一個(gè)Service方法,,在該Service方法中調(diào)用多個(gè)Dao方法,,所有在該Service方法中的的Dao都處于同一事務(wù)中。

該Service方法結(jié)束后,,提交事務(wù),;

該Service方法中有任何錯(cuò),回滾事務(wù),;

2.2 傳統(tǒng)的做法

來(lái)看下面這段偽代碼

Service層代碼:

public void serviceMethod(){

Connection conn=null;

try{

Connection conn=getConnection();

conn.setAutoCommit(false);

Dao1 dao1=new Dao1(conn);

dao1.doSomething();

Dao2 dao2=new Dao2(conn);

dao2.doSomething();

Dao3 dao3=new Dao3(conn);

dao3.doSomething();
        conn.commit();

}catch(Exception e){

    try{

    conn.rollback();

}catch(Exception ex){}

}finally{

try{

conn.setAutoCommit(true);

}catch(Exception e){}

    try{

    if(conn!=null){

    conn.close();

    conn=null;

}

}catch(Exception e){}

}

}

每個(gè)Dao層的代碼:

Class Dao1{

private Connection conn=null;

public Dao1(Connection conn){

    this.conn=conn;

}

public void doSomething(){

    PreparedStatement pstmt=null;

    try{

        pstmt=conn.preparedStatement(sql);

        pstmt.execute…

        …

}catch(Exception e){

    log.error(e,”Exeception occurred in Dao1.doSomething():”+e.getMessage,e);

}finally{

    try{

        if(pstmt!=null){

            pstmt.close();

            pstmt=null;

}

    }catch(Exception e){}

}

}

}

如果我一個(gè)Service方法有調(diào)用一堆dao方法,,先不說(shuō)這樣寫首先破壞了OOP的封裝性原則,如果有一個(gè)dao多關(guān)了一個(gè)conn,,那就會(huì)導(dǎo)致其它的dao得到的conn為null,,這種事在這樣的寫法下由其當(dāng)你還有業(yè)務(wù)邏輯混合在一起時(shí)很容易發(fā)生。

筆者曾經(jīng)遇見過(guò)2個(gè)項(xiàng)目,,出現(xiàn)out of memory或者是connection pool has been leakage,,經(jīng)查代碼就是在每個(gè)dao中多關(guān)或者在service層中漏關(guān),或者是每個(gè)dao有自己的conntionconn=getConnection(),,然后還跑到Service層里去關(guān)這個(gè)connection(那關(guān)什么,,關(guān)個(gè)P關(guān)!),。

當(dāng)然,,如果你說(shuō)你在寫法上絕對(duì)promise絕對(duì)注意這樣的問(wèn)題不會(huì)發(fā)生,但是我們來(lái)看看下面的這種做法,,是否會(huì)比上面這個(gè)寫法更好呢,?

 2.3 Spring中的做法

先來(lái)看Spring中的寫法。

大家應(yīng)該都很熟悉Spring中的寫法了,,來(lái)看一下它是怎么解決的,。

Service層

public void serviceMethod(){

try{

    //aop 自動(dòng)加入connection,并且將conn.setAutoCommit(false);

dao1.doSomething();

dao2.doSomething();

dao3.doSomething();

}catch(Exception e){

    //aop 自動(dòng)加入rollback

}finally{

    //aop自動(dòng)加入conn.setAutoCommit(true)

    //aop 自動(dòng)加入conn.close();

}

 

這邊我們不講AOP,,因?yàn)橛妙惙瓷浣Y(jié)合xml很容易將aop 自動(dòng),。。,。這些東西加入我們的代碼中去是不是,?我們只管寫dao方法,service方法,,不需要關(guān)心在哪邊commit哪邊rollback何時(shí)connection,,spring的聲明式事務(wù)會(huì)幫我們負(fù)責(zé),這種風(fēng)格我們稱為“優(yōu)雅”,,各層間耦合度極大程度上的降低,,封裝性好,。

因此,我們可以總結(jié)出下面這些好處:

2  Service層的方法只管開啟事務(wù)(如果講究點(diǎn)的還會(huì)設(shè)一個(gè)Transaction),;

2  在該Service層中的所有dao使用該service方法中開啟的事務(wù)(即connection),;

2  Dao中每次只管getCurrentConnection(獲取當(dāng)前的connection),與進(jìn)行數(shù)據(jù)處理

2  Dao層中如果發(fā)生錯(cuò)誤就拋回Service層

2  Service層中接到exception,,在catch{}中rollback,,在try{}未尾commit,在finally塊中關(guān)閉整個(gè)connection,。

這,。。,。就是我們所說(shuō)的ThreadLocal,。

舉個(gè)更實(shí)際的例子再次來(lái)說(shuō)明ThreadLocal:

我們有3個(gè)用戶訪問(wèn)同一個(gè)service方法,該service方法內(nèi)有3個(gè)dao方法為一個(gè)完整事務(wù),,那么整個(gè)web容器內(nèi)只因該有3個(gè)connection,,并且每個(gè)connection之間的狀態(tài),彼此“隔離”,。

我們下面一起來(lái)看我們?nèi)绾斡么a實(shí)現(xiàn)類似于Spring的這種做法,。

首先,根據(jù)我們的ThreadLocal的概念,,我們先聲明一個(gè)ConnectionManager的類,。

2.4 利用ThreadLocal制作ConnectionManager

public class ConnectionManager {

         private static ThreadLocal tl = new ThreadLocal();

         private static Connection conn = null;

         public static void BeginTrans(boolean beginTrans) throws Exception {

                   if (tl.get() == null || ((Connection) tl.get()).isClosed()) {

                            conn = SingletonDBConnection.getInstance().getConnection();

                            conn = new ConnectionSpy(conn);

                            if (beginTrans) {

                                     conn.setAutoCommit(false);

                            }

                            tl.set(conn);

                   }

         }

         public static Connection getConnection() throws Exception {

                   return (Connection) tl.get();

         }

         public static void close() throws SQLException {

                   try {

                            ((Connection) tl.get()).setAutoCommit(true);

                   } catch (Exception e) {

                   }

                   ((Connection) tl.get()).close();

                   tl.set(null);

         }

         public static void commit() throws SQLException {

                   try {

                            ((Connection) tl.get()).commit();

                   } catch (Exception e) {

                   }

                   try {

                            ((Connection) tl.get()).setAutoCommit(true);

                   } catch (Exception e) {

                   }

         }

         public static void rollback() throws SQLException {

                   try {

                            ((Connection) tl.get()).rollback();

                   } catch (Exception e) {

                   }

                   try {

                            ((Connection) tl.get()).setAutoCommit(true);

                   } catch (Exception e) {

                   }

         }

}

2.5 利用ThreadLocal改造Service與Dao層

Service層(注意紅色標(biāo)粗-好粗yeah,的地方

package sky.org.service.impl;

public class StudentServiceImpl implements StudentService {

         public void addStudent(Student std) throws Exception {

                   StudentDAO studentDAO = new StudentDAOImpl();

                   ClassRoomDAO classRoomDAO = new ClassRoomDAOImpl();

                   try {

                            ConnectionManager.BeginTrans(true);

                            studentDAO.addStudent(std);

                            classRoomDAO

                                               .addStudentClassRoom(std.getClassRoomId(), std.getsNo());

                            ConnectionManager.commit();

                   } catch (Exception e) {

                            try {

                                     ConnectionManager.rollback();

                            } catch (Exception de) {

                            }

                            throw new Exception(e);

                   }finally {

                            try {

                                     ConnectionManager.close();

                            } catch (Exception e) {

                            }

                   }

         }

}

Look,,如果我把上述標(biāo)粗(沒(méi)有加紅色)的地方,,全部用AOP的方式從這塊代碼的外部“切”進(jìn)去。,。,。是不是一個(gè)Spring里的Service方法就誕生了?

下面來(lái)看一個(gè)完整的例子

2.6 使用ThreadLocal分離Service,、DAO層

先來(lái)看表結(jié)構(gòu):

T_Student表

T_ClassRoom表

T_Student_ClassRoom表

需求:

很簡(jiǎn)單,T_ClassRoom表里已經(jīng)有值了,,在插入T_Student表的數(shù)據(jù)時(shí)同時(shí)要給這個(gè)學(xué)生分配一個(gè)班級(jí)并且插入T_Student_ClassRoom表,,這就是一個(gè)事務(wù),這兩步中有任何一步出錯(cuò),,事務(wù)必須回滾,。

看來(lái)工程的結(jié)構(gòu)吧:

下面開始放出所有源代碼:

2.6.1 ConnectionManager

package sky.org.util.db;

import java.sql.*;

public class ConnectionManager {

         private static ThreadLocal tl = new ThreadLocal();

         private static Connection conn = null;

         public static void BeginTrans(boolean beginTrans) throws Exception {

                   if (tl.get() == null || ((Connection) tl.get()).isClosed()) {

                            conn = DBConnection.getInstance().getConnection();

                            conn = new ConnectionSpy(conn);

                            if (beginTrans) {

                                     conn.setAutoCommit(false);

                            }

                            tl.set(conn);

                   }

         }

         public static Connection getConnection() throws Exception {

                  return (Connection) tl.get();

         }

         public static void close() throws SQLException {

                   try {

                            ((Connection) tl.get()).setAutoCommit(true);

                   } catch (Exception e) {

                   }

                   ((Connection) tl.get()).close();

                   tl.set(null);

         }

         public static void commit() throws SQLException {

                   try {

                            ((Connection) tl.get()).commit();

                   } catch (Exception e) {

                   }

                   try {

                            ((Connection) tl.get()).setAutoCommit(true);

                   } catch (Exception e) {

                   }

         }

         public static void rollback() throws SQLException {

                   try {

                            ((Connection) tl.get()).rollback();

                   } catch (Exception e) {

                   }

                   try {

                            ((Connection) tl.get()).setAutoCommit(true);

                   } catch (Exception e) {

                   }

         }

}

2.6.2 DBConnection

package sky.org.util.db;

public class DBConnection {

         private static DBConnection instance = null;

         private static String driverClassName = null;

         private static String connectionUrl = null;

         private static String userName = null;

         private static String password = null;

         private static Connection conn = null;

         private static Properties jdbcProp = null;

         private DBConnection() {

         }

         private static Properties getConfigFromPropertiesFile() throws Exception {

                   Properties prop = null;

                   prop = JdbcProperties.getPropObjFromFile();

                   return prop;

         }

         private static void initJdbcParameters(Properties prop) {

                   driverClassName = prop.getProperty(Constants.DRIVER_CLASS_NAME);

                   connectionUrl = prop.getProperty(Constants.CONNECTION_URL);

                   userName = prop.getProperty(Constants.DB_USER_NAME);

                   password = prop.getProperty(Constants.DB_USER_PASSWORD);

         }

         private static void createConnection() throws Exception {

                   Class.forName(driverClassName);

                   conn = DriverManager.getConnection(connectionUrl, userName, password);

         }

         public static Connection getConnection() throws Exception {

                   return conn;

         }

         public synchronized static DBConnection getInstance()throws Exception{

                   if (instance == null) {

                            jdbcProp = getConfigFromPropertiesFile();

                            instance = new DBConnection();

                   }

                   initJdbcParameters(jdbcProp);

                   createConnection();

                   return instance;

         }

}

2.6.3 JdbcProperties

package sky.org.util.db;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.InputStream;

import java.net.URL;

import java.util.*;

public class JdbcProperties {

         private static Log logger = LogFactory.getLog(JdbcProperties.class);

         public static Properties getPropObjFromFile() {

                   Properties objProp = new Properties();

                   ClassLoader classLoader = Thread.currentThread()

                                     .getContextClassLoader();

                   URL url = classLoader.getResource(Constants.JDBC_PROPERTIES_FILE);

                   if (url == null) {

                            classLoader = ClassLoader.getSystemClassLoader();

                            url = classLoader.getResource(Constants.JDBC_PROPERTIES_FILE);

                   }

                   File file = new File(url.getFile());

                   InputStream inStream = null;

                   try {

                            inStream = new FileInputStream(file);

                            objProp.load(inStream);

                   } catch (FileNotFoundException e) {

                            objProp = null;

                            e.printStackTrace();

                   } catch (IOException e) {

                            e.printStackTrace();

                   } finally {

                            try {

                                     if (inStream != null) {

                                               inStream.close();

                                               inStream = null;

                                     }

                            } catch (Exception e) {

                            }

                   }

                   return objProp;

         }

}

2.6.4 Resource目錄下的jdbc.properties

jdbc.driverClassName=com.mysql.jdbc.Driver

jdbc.databaseURL=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8

jdbc.username=mysql

jdbc.password=password_1

2.6.5 StudentService接口

package sky.org.service;

import java.util.List;

import java.util.Vector;

import sky.org.bean.*;

public interface StudentService {

         public void addStudent(Student std) throws Exception;

}

2.6.6 StudentServiceImpl

package sky.org.service.impl;

import java.util.ArrayList;

import java.util.List;

import java.util.Vector;

import sky.org.util.db.ConnectionManager;

import sky.org.util.*;

import sky.org.bean.*;

import sky.org.dao.*;

import sky.org.dao.impl.*;

import sky.org.service.*;

public class StudentServiceImpl implements StudentService {

 

         public void addStudent(Student std) throws Exception {

                   StudentDAO studentDAO = new StudentDAOImpl();

                   ClassRoomDAO classRoomDAO = new ClassRoomDAOImpl();

                   try {

                            ConnectionManager.BeginTrans(true);

                            studentDAO.addStudent(std);

                            classRoomDAO

                                               .addStudentClassRoom(std.getClassRoomId(), std.getsNo());

                            ConnectionManager.commit();

                   } catch (Exception e) {

                            try {

                                     ConnectionManager.rollback();

                            } catch (Exception de) {

                            }

                            throw new Exception(e);

                   } finally {

                            try {

                                     ConnectionManager.close();

                            } catch (Exception e) {

                            }

                   }

         }

}

2.6.7 ClassRoomDAO接口

package sky.org.dao;

import java.util.HashMap;

import java.util.List;

public interface ClassRoomDAO {

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

}

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類(運(yùn)行主類)

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在事務(wù)操作中也支持ThreadLocal的作法,,我們這邊指的是不用Spring去做代理,,而直接用Hibernate,。即:

Service Method{

hbDAO1.doSomething();

hbDAO2.doSomething();

hbDAO3.doSomething();

。,。,。

}

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

3.1 getCurrentSession與openSession的區(qū)別

3.1.1 openSession

我們傳統(tǒng)的做法是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塊中正確關(guān)閉session,但是,,如果我們也遇上了這樣的case即:

Service Method{

hbDAO1.doSomething();

hbDAO2.doSomething();

hbDAO3.doSomething();

,。。,。

}

這時(shí),,我們?nèi)绻玫氖莖penSession,應(yīng)該怎么辦,?

解決方案一:

自己用ThreadLocal模式寫一個(gè)SessionManagement類,,來(lái)維護(hù)這個(gè)session。

解決方案二:

把在Service方法中打開的session,,傳到每個(gè)dao方法中,,使每個(gè)dao方法使用同一個(gè)session,最后在Service方法中去關(guān)閉它(很爛的做法),。

下面我們來(lái)看看Hibernate自身提供的getCurrentSession()的做法吧

3.1.2 getCurrentSession

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

<?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE hibernate-configuration PUBLIC

          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

          "http://hibernate./hibernate-configuration-3.0.dtd">

<hibernate-configuration>

         <session-factory>

                   <property name="connection.url">

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

                   </property>

                   <property name="dialect">

                            org.hibernate.dialect.Oracle9Dialect

                   </property>

                   <property name="connection.username">abc</property>

                   <property name="connection.password">abc</property>

                   <property name="connection.driver_class">

                            oracle.jdbc.OracleDriver

                   </property>

                   <property name="show_sql">true</property>

                   <property name="hibernate.hbm2ddl.auto">update</property>

                   <property name="hibernate.current_session_context_class">thread</property>

                   <mapping resource="com/cts/testhb/model/TUser.hbm.xml" />

         </session-factory>

</hibernate-configuration>

然后上述代碼將變成如下的樣子:

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

                   }

         }

而你的每個(gè)DAO方法中的代碼是這樣實(shí)現(xiàn)的:

public void addUser(TUser user) throws Exception {

         SessionFactory factory = HibernateUtil.getInstance()

                            .getSessionFactory();

         Session session = factory.getCurrentSession();

         session.save(user);

}

是不是很方便的哈。

3.1.3 openSession與getCurrentSession的區(qū)別

嚴(yán)重注意下面3點(diǎn):

2  openSession一旦被調(diào)用,,必須且一定要在finally塊中close,,要不然你就等著out of memory吧;

2  如果你使用的是getCurrentSession,,那么你不能在finally塊中調(diào)用”session.close()”,,不行你可以在finally塊中用try-catch把session.close();包起來(lái),然后在catch{}塊中拋出這個(gè)exception,,這個(gè)exception將會(huì)是:sessionhas been already closed,。

因?yàn)椋?/p>

l   如果你用的是getCurrentSession,那么它在session.commit()或者是session.rollback()時(shí)就已經(jīng)調(diào)用了一次session.close()了,,因此你只要正確放置session.commit()與rollback()即可,。

l   你必須在finally塊中調(diào)用”ThreadLocalSessionContext.unbind(factory);”,以使得當(dāng)前的事務(wù)結(jié)束時(shí)把session(即dbconnection)還回db connection pool中

2  如果你使用的是getCurrentSession,,那么就算你是一個(gè)簡(jiǎn)單的select語(yǔ)句,,也必須包含在:

tran = session.beginTransaction();

//your select hibernate query

tran.commit();

這樣的事務(wù)塊中,要不然它將會(huì)拋出這樣的一個(gè)錯(cuò)誤:

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()結(jié)束的,,如果,,你把你的hibernate查詢移到了tran=session.beginTransaction的上面,。。,。就會(huì)拋上述這個(gè)錯(cuò)誤,。

3.1.4 getCurrentSession帶來(lái)的問(wèn)題

getCurrentSession非常好,不需要我們自己寫ThreadLocal只需要在hibernate.cfg的配置文件中聲音一下就可以獲得ThreadLocal的好處,,便于我們劃分我們的程序的層次與封裝,,帶也帶來(lái)了一定的性能問(wèn)題。

特別是“如果你使用的是getCurrentSession,,那么就算你是一個(gè)簡(jiǎn)單的select語(yǔ)句,,也必須包含在事務(wù)塊中”。這給我們帶來(lái)了很大的問(wèn)題,。

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

1.       一個(gè)service方法中只有單個(gè)dao操作且此操作是一個(gè)select類的操作,,請(qǐng)使用openSession,,并且即時(shí)在finally塊中關(guān)閉它;

2.       如果一個(gè)service方法中涉及到多個(gè)dao操作,,請(qǐng)一定使用getCurrentSession,;

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

1)      將屬于select的操作,,單獨(dú)做成一個(gè)dao方法,該dao使用openSession并且在finally塊中及時(shí)關(guān)閉session,該dao只需要返回一個(gè)java的object如:List<Student>即可,,如果出錯(cuò)將exception拋回給調(diào)用它的service方法,。

2)      對(duì)于其它的delete, insert, update的dao操作,請(qǐng)使用getCurrentSession,。

4.       忌諱,,把select類的操作放在“事務(wù)”中;



    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多