三大框架顧名思義就是非常有名的Struts2 ,Hibernate,Spring,
框架整合的方法很多,現在我寫一個非常簡單的整合過程,相信大家一看就會!
這里使用的struts-2.2.1.1、hibernate-3.2.0、spring2.5.6
第一步,搭建Struts2環境
1、導入struts2的jar包(直接把struts-blank項目下的依賴庫coypy到自己項目中)
2、 配置web.xml,增加struts2提供的過濾器(參考struts-blank項目)

1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 8 <filter> 9 <filter-name>struts2</filter-name> 10 <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> 11 </filter> 12 13 <filter-mapping> 14 <filter-name>struts2</filter-name> 15 <url-pattern>/*</url-pattern> 16 </filter-mapping> 17 18 </web-app>
3、建立包:com.qcf.struts.test,並增加普通java類,代碼如下:

1 package com.qcft.struts.test; 2 3 public class FirstAction { 4 5 private String msg; 6 7 public String execute() throws Exception{ 8 System.out.println("FirstAction.test1()"); 9 setMsg("為了讓生活美好!"); 10 return "success"; 11 } 12 13 public String getMsg() { 14 return msg; 15 } 16 17 public void setMsg(String msg) { 18 this.msg = msg; 19 } 20 }
4、在src下增加struts.xml,並增加FirstAction類的配置內容:

1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 4 "http://struts.apache.org/dtds/struts-2.0.dtd"> 5 6 <struts> 7 <package name="default" namespace="/" extends="struts-default"> 8 <action name="first" class="com。qcf.struts.test.FirstAction"> 9 <result name="success">ok.jsp</result> 10 </action> 11 </package> 12 <!-- Add packages here --> 13 </struts>
5、增加ok.jsp頁面,用來顯示FirstAction中的屬性msg:

1 <%@ page language="java" import="java.util.*" pageEncoding="gbk"%> 2 <%@ taglib prefix="s" uri="/struts-tags" %> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>測試struts2</title> 7 </head> 8 <body> 9 <s:property value="msg" /> 10 </body> 11 </html>
測試成功!
第二步:搭建Hibernate環境
1、導入hibernate所需要的基本的jar包
2、添加hibernate.cfg.xml配置文件
打開etc目錄,將hibernate.cfg.xml拷貝到項目src下
修改配置文件hibernate.cfg.xml內容,結合etc/hibernate.properties(文件中搜索”mysql”),完成后配置內容如下:

1 <!DOCTYPE hibernate-configuration PUBLIC 2 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 4 <hibernate-configuration> 5 <session-factory> 6 <property name="show_sql">true</property> 7 <property name="hibernate.dialect"> 8 org.hibernate.dialect.MySQLDialect 9 </property> 10 <property name="connection.driver_class"> 11 com.mysql.jdbc.Driver 12 </property> 13 <property name="hibernate.connection.url"> 14 jdbc:mysql://localhost:3306/testhib 15 </property> 16 <property name="connection.username"> 17 root 18 </property> 19 <property name="connection.password"> 20 123456 21 </property> 22 </session-factory> 23 </hibernate-configuration>
3、新建pojo類(Plain Old Java Objects 簡單的java對象,實際上就是我們講的普通javabean對象):User

1 package com.qcf.hib.bean; 2 3 import java.util.Date; 4 5 public class User { 6 private int id; 7 private String name; 8 private Date birthday; 9 10 public int getId() { 11 return id; 12 } 13 public void setId(int id) { 14 this.id = id; 15 } 16 public String getName() { 17 return name; 18 } 19 public void setName(String name) { 20 this.name = name; 21 } 22 public Date getBirthday() { 23 return birthday; 24 } 25 public void setBirthday(Date birthday) { 26 this.birthday = birthday; 27 } 28 public User(int id, String name, Date birthday) { 29 super(); 30 this.id = id; 31 this.name = name; 32 this.birthday = birthday; 33 } 34 public User(String name, Date birthday) { 35 super(); 36 this.name = name; 37 this.birthday = birthday; 38 } 39 40 public User() { 41 } 42 }
4、增加映射文件User.hbm.xml(寫法可以參考:eg/User.hbm.xml)
映射文件hbm.xml說明了pojo類和表的對應關系,以及pojo類中屬性和表中字段的對應關系。
注:本映射文件增加到跟pojo同一個包中

1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 5 <hibernate-mapping 6 package="com.qcf.hib.bean"> 7 <class name="User" table="_user" lazy="true"> 8 <id name="id"> 9 <generator class="native"/> 10 </id> 11 <property name="name" type="java.lang.String" 12 not-null="true" 13 length="15" 14 column="_name"/> 15 <property name="birthday" type="java.util.Date" column="birthday"/> 16 </class> 17 </hibernate-mapping>
5、在hibernate.cfg.xml中增加User.hbm.xml文件的配置,讓hibernate知道本映射關系。在<session-factory>元素下增加:
<mapping resource="com/qcf/hib/bean/User.hbm.xml"/>
6、修改hibernate.cfg.xml文件,在<session-factory>下增加hbm2ddl.auto的配置:
<property name="hibernate.hbm2ddl.auto">update</property>
create-drop: 運行時,先創建,運行完,在刪除。
create:每次運行前都會刪除已有的。在創建。 測試時,可以使用create.
update:映射文件和表。不會重新創建表及不會重新執行ddl語句,只會更新表中的記錄。
validate:看映射文件和表是不是對應,如果不對應,他也不會更新,會報錯。經常用它,保險一些。
7、增加Test.java測試類:

1 package com.bjsxt.hib.test; 2 3 import java.util.Date; 4 5 import org.hibernate.Session; 6 import org.hibernate.SessionFactory; 7 import org.hibernate.cfg.Configuration; 8 9 import com.bjsxt.hib.bean.User; 10 11 public class Test { 12 public static void main(String[] args) { 13 Configuration conf = new Configuration().configure(); 14 SessionFactory factory = conf.buildSessionFactory(); 15 Session session = factory.openSession(); 16 User user = new User("高淇",new Date()); 17 session.save(user); 18 session.close(); 19 } 20 }
8、 上一次執行,我們發現表創建成功但是數據記錄並沒有插入表中。jdbc是自動提交,autocommit。hibernate缺省是false. 因此,我們必須很明確的開啟事務才行。我們將Test.java文件內容修改如下:

1 package com.qcf.hib.test; 2 3 import java.util.Date; 4 5 import org.hibernate.Session; 6 import org.hibernate.SessionFactory; 7 import org.hibernate.Transaction; 8 import org.hibernate.cfg.Configuration; 9 10 import com.bjsxt.hib.bean.User; 11 12 public class Test { 13 public static void main(String[] args) { 14 Configuration conf = new Configuration().configure(); 15 SessionFactory factory = conf.buildSessionFactory(); 16 Session session = factory.openSession(); 17 Transaction transaction = session.beginTransaction(); 18 19 User user = new User("高淇",new Date()); 20 session.save(user); 21 22 transaction.commit();//保存之后,關閉session之前,顯示提交事務.(必須調用,不然不會提交。即使session關閉,也不回自動提交) 23 session.close(); 24 } 25 }
測試成功,數據庫中也有相應的數據添加成功!
第三步:搭建Spring環境
1、導入Spring所需要的jar包
spring.jar這一個即可!
2、寫一個測試類

1 package com.qcf.test; 2 3 public class UserDao { 4 public void add(String uname,String pwd){ 5 System.out.println("增加一個用戶!"); 6 } 7 }
3、增加配置文件beans.xml,內容如下:

1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> 8 9 <bean id="userDao" class="com.sxt.test.UserDao"></bean> 10 11 </beans>
通過上面的配置文件,spring框架知道了UserDao類的存在!可以通過反射機制自動將UserDao類的對象new出! 所以注意托管給spring的類必須符合基本的javabean規范:
1. 如果有屬性,則必須有相應的get/set方法。
2. 必須要無參的構造器
4、建立Test.java類

1 package com.qcf.test; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 public class Test { 7 public static void main(String[] args){ 8 // UserDao userDao = new UserDao(); 9 // userDao.add("a", "123"); 10 11 ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"beans.xml"}); 12 UserDao userdao = (UserDao) context.getBean("userDao"); 13 userdao.add("d", "222"); 14 } 15 }
5、上面的代碼中,我們可以使用context.getBean("userDao")代替了new UserDao(這樣的代碼,也就是spring內部有個工廠類,替我們完成了new對象的操作!而這個工廠類是通過讀取beans.xml文件知道了字符串”userDao”和com.sxt.test.UserDao類之間的關系!
直接運行Test.java類即可。
第四步:已經將三個框架各自搭建完畢。現在先整合Struts和spring
整合struts2和spring非常簡單只需兩步:
1、在web.xml下面添加一個spring的過濾器(添加到最上面,在struts2的配置文件上面)
1 <listener> 2 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 3 </listener> 4 <context-param> 5 <param-name>contextConfigLocation</param-name> 6 <param-value>classpath:application.xml</param-value> 7 </context-param>
2、添加一個struts-spring.plus的插件,這個可以再struts官方提供的jar中即可找到
注:action中的class不用填寫全名,直接寫spring中注冊的id即可,如:testAction
1 <package name="default" namespace="/" extends="struts-default"> 2 <action name="testAction" class="testAction"> 3 <result name="success">index.jsp</result> 4 </action> 5 </package>
第五步:整合spring和hibernate
1、首先將web.xml添加頭文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xmlns:tx="http://www.springframework.org/schema/tx" 6 xmlns:context="http://www.springframework.org/schema/context" 7 xsi:schemaLocation=" 8 http://www.springframework.org/schema/beans 9 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 10 http://www.springframework.org/schema/tx 11 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd 12 http://www.springframework.org/schema/aop 13 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 14 http://www.springframework.org/schema/context 15 http://www.springframework.org/schema/context/spring-context-2.5.xsd 16 ">
2、配置sessionFactory(配置了C3P0數據庫連接池)
<!-- 導入jdbc.properties --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置sessionfactory --> <bean name="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <!-- 配置application.xml路徑 --> <property name="configLocation" value="classpath:hibernate.cfg.xml"></property> <!-- 配置c3p0連接池 --> <property name="dataSource"> <bean class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 數據庫連接信息 --> <property name="driverClass" value="${driverClass}"></property> <property name="jdbcUrl" value="${jdbcUrl}"></property> <property name="user" value="${user}"></property> <property name="password" value="${password}"></property> <!-- 其它配置 --> <!-- 數據庫初始化時獲取三個鏈接,取值應該在min --> <property name="initialPoolSize" value="3"></property> <!-- 連接池中保留的最小連接數 --> <property name="minPoolSize" value="3"></property> <!-- 連接池中保留的最大連接數 --> <property name="maxPoolSize" value="10"></property> <!-- 當連接池中連接耗盡時c3p0一次獲取的連接數 --> <property name="acquireIncrement" value="3"></property> <!-- 配置數據源內加載的preparestatement數量 --> <property name="maxStatements" value="3"></property> <!-- 單個連接所擁有的最大statments緩存數 --> <property name="maxStatementsPerConnection" value="3"></property> <!-- 設置最大空閑時間不使用自動丟棄,如果為0永遠不丟棄 --> <property name="maxIdleTime" value="1800"></property> </bean> </property> </bean>
3、配置事務管理(XML)
1 <!-- 配置聲明事務管理 --> 2 <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 3 <property name="sessionFactory" ref="sessionFactory"></property> 4 </bean> 5 <!-- AOP核心配置 --> 6 <aop:config> 7 <!-- 定義aop切面 --> 8 <aop:pointcut expression="execution(public * com.qcf.test.*.*(..))" id="testa"/> 9 <aop:advisor advice-ref="txadvice" pointcut-ref="testa"/> 10 </aop:config> 11 <!-- 定義切割方法 --> 12 <tx:advice id="txadvice" transaction-manager="txManager"> 13 <tx:attributes> 14 <tx:method name="save*" propagation="REQUIRED"/> 15 </tx:attributes> 16 </tx:advice> 17 <!-- -->
配置事務(annotation)
1 <!-- 自動掃面 2 --> 3 <context:component-scan base-package="com.qcf"></context:component-scan> 4 5 6 <!-- 配置事務 --> 7 <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 8 <property name="sessionFactory" ref="sessionFactory"></property> 9 </bean> 10 11 <!-- annotation配置事務 --> 12 <tx:annotation-driven transaction-manager="txManager"/>
測試方法:

1 package com.qcf.dao.impl; 2 3 import javax.annotation.Resource; 4 5 import org.hibernate.Session; 6 import org.hibernate.SessionFactory; 7 import org.springframework.stereotype.Controller; 8 import org.springframework.stereotype.Service; 9 import org.springframework.transaction.annotation.Transactional; 10 11 import com.qcf.dao.UserDao; 12 import com.qcf.po.User; 13 14 @Service 15 public class UserDaoImpl implements UserDao { 16 17 @Resource 18 private SessionFactory sessionFactory; 19 /** 20 * 增加用戶 21 */ 22 @Transactional 23 public void addUser() { 24 // TODO Auto-generated method stub 25 Session session=sessionFactory.getCurrentSession(); 26 session.save(new User(0, "zhangsan", 19)); 27 session.save(new User(0, "zhan", 19)); 28 29 } 30 public SessionFactory getSessionFactory() { 31 return sessionFactory; 32 } 33 public void setSessionFactory(SessionFactory sessionFactory) { 34 this.sessionFactory = sessionFactory; 35 } 36 37 38 39 }
4、配置HibernateTemplate
HibernateTemplate類可讓我們將Hibernate的使用模板化,使我們對hibernate的調用更加簡單!使用他,我們只需要在配置文件中增加:
1 <!-- 配置hibernatetempter --> 2 <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> 3 <property name="sessionFactory" ref="sessionFactory"></property> 4 </bean> 5
hibernateTemplate常用方法:
◦ void delete(Object entity):刪除指定持久化實例
◦ deleteAll(Collection entities):刪除集合內全部持久化類實例
◦ find(String queryString):根據HQL查詢字符串來返回實例集合
◦ get(Class entityClass, Serializable id):根據主鍵加載特定持久化類的實例
◦ save(Object entity):保存新的實例
◦ saveOrUpdate(Object entity):根據實例狀態,選擇保存或者更新
◦ update(Object entity):更新實例的狀態,要求entity是持久狀態
◦ setMaxResults(int maxResults):設置分頁的大小(無setFirstResult方法)
HibernateTemplate的典型用法:
-
- 需要直接獲得session對象的處理方式(比如:分頁處理)
1 hibernateTemplate.execute(new HibernateCallback() { 2 3 public Object doInHibernate(Session session) throws HibernateException, 4 SQLException { 5 // TODO Auto-generated method stub 6 session.save(new User(0, "lisi", 19)); 7 return null; 8 } 9 });
2. 不需要直接獲得session對象的情況
1 public List<User> getAllUser(){ 2 List<User> list=hibernateTemplate.find("from User"); 3 for (int i = 0; i < list.size(); i++) { 4 System.out.println(list.get(i).getId()); 5 6 } 7 8 List list2 = hibernateTemplate.find("from User where name=? and id=?", new Object[]{"zhangsan",1}); 9 for (int i = 0; i < list2.size(); i++) { 10 System.out.println(list2.get(i).toString()); 11 } 12 13 return null; 14 }
5、HibernateDaoSupport
封裝了HibernateTemplate!常見用法如下:
public class UserDaoImpl3 extends HibernateDaoSupport { public void add(User u) { this.getHibernateTemplate().save(u); } } public class UserDaoImpl3 extends HibernateDaoSupport { public void add(User u) { Session s = this.getSession(); s.save(u); releaseSession(s); //手動釋放session資源 } }
6、JDBCTemplate的使用
dbcTemplate類是spring為了讓我們更加容易使用jdbc而提供的封裝。JdbcTemplate對jdbc操作做了簡單的封裝。內部也使用了類似HibernateTemplate中使用的模板方法模式。JdbcTemplate在工作中用的不多。本節為自學內容,目的是讓大家開闊眼界。
要使用JdbcTemplate,我們必須要在spring中增加配置:
1 <!--配置一個JdbcTemplate實例--> 2 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 3 <property name="dataSource" ref="dataSource"/> 4 </bean>
測試類如下:

1 package com.qcf.dao.impl; 2 3 import java.sql.ResultSet; 4 import java.sql.SQLException; 5 import java.util.List; 6 import java.util.Map; 7 8 import javax.annotation.Resource; 9 10 import org.springframework.context.ApplicationContext; 11 import org.springframework.context.support.ClassPathXmlApplicationContext; 12 import org.springframework.jdbc.core.JdbcTemplate; 13 import org.springframework.jdbc.core.RowMapper; 14 import org.springframework.stereotype.Component; 15 16 import com.sxt.po.User; 17 18 /** 19 * 用來測試jdbcTemplate的用法 20 * @author Administrator 21 * 22 */ 23 @Component("userDao") 24 public class UserDaoImpl { 25 @Resource 26 private JdbcTemplate jdbcTemplate; 27 28 public void testInsertUser(User user){ 29 jdbcTemplate.update("insert into user (uname,pwd) values (?,?)",new Object[]{user.getUname(),user.getPwd()}); 30 } 31 32 public void testUpdateUser(String pwd,int id){ 33 jdbcTemplate.update("update user set pwd=? where id=?",new Object[]{pwd,id}); 34 } 35 public void deleteUser(int id){ 36 jdbcTemplate.update("delete from user where id=?",new Object[]{id}); 37 } 38 39 public void testGetUserById(int id){ 40 User user = (User) jdbcTemplate.queryForObject("select id,uname,pwd from user where id=?", new Object[]{id}, new RowMapper(){ 41 @Override 42 public Object mapRow(ResultSet rs, int no) throws SQLException { 43 User u = new User(); 44 u.setId(rs.getInt("id")); 45 u.setUname(rs.getString("uname")); 46 u.setPwd(rs.getString("pwd")); 47 return u; 48 }}); 49 50 System.out.println(user.getUname()); 51 } 52 53 public void testGetUsers(){ 54 List<Map> list = jdbcTemplate.queryForList("select * from user where id>?",new Object[]{1}); 55 for (Map map : list) { 56 System.out.println(map.get("uname")); 57 } 58 } 59 public static void main(String[] args) { 60 ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"}); 61 UserDaoImpl ud = (UserDaoImpl) context.getBean("userDao"); 62 User u = new User(); 63 u.setUname("sss"); 64 u.setPwd("123"); 65 // ud.testInsertUser(u); 66 // ud.testDeleteUser(2); 67 ud.testGetUsers(); 68 } 69 70 }
7、OpenSessionInView管理session
OpenSessionInViewFilter是Spring提供的一個針對Hibernate的一個支持類,其主要意思是在發起一個頁面請求時打開 Hibernate的Session,一直保持這個Session,直到這個請求結束,具體是通過一個Filter來實現的。
由於Hibernate引入了Lazy Load特性,使得脫離Hibernate的Session周期的對象如果再想通過getter方法取到其關聯對象的值,Hibernate會拋出一個 LazyLoad的Exception。所以為了解決這個問題,Spring引入了這個Filter,使得Hibernate的Session的生命周期變長。
OpenSessionInViewFilter:org.springframework.orm.hibernate3.support.OpenSessionInViewFilter]是 Spring提供的一個針對Hibernate的一個支持類,其主要意思是在發起一個頁面請求時打開Hibernate的Session,一直保持這個 Session,直到這個請求結束,具體是通過一個Filter來實現的。
由於Hibernate引入了Lazy Load特性,使得脫離Hibernate的Session周期的對象如果再想通過getter方法取到其關聯對象的值,Hibernate會拋出一個 LazyLoad的Exception。所以為了解決這個問題,Spring引入了這個Filter,使得Hibernate的Session的生命周期 變長。
有兩種方式可以配置實現OpenSessionInView,分別是 OpenSessionInViewInterceptor和OpenSessionInViewFilter,功能完全相同,只不過一個在 web.xml配置,另一個在application.xml配置而已。
我們可以在web.xml中配置opensessioninview,代碼如下:
1 <!-- 配置Spring自動管理Session. 要配置到struts過濾器之前!--> 2 <filter> 3 <filter-name>hibernateSessionFilter</filter-name> 4 <filter-class> 5 org.springframework.orm.hibernate3.support.OpenSessionInViewFilter 6 </filter-class> 7 </filter> 8 <filter-mapping> 9 <filter-name>hibernateSessionFilter</filter-name> 10 <url-pattern>/*</url-pattern> 11 </filter-mapping>
8、ThreadLocal模式管理session
我們知道Session是由SessionFactory負責創建的,而SessionFactory的實現是線程安全的,多個並發的線程可以同時訪問一 個SessionFactory並從中獲取Session實例,那么Session是否是線程安全的呢?很遺憾,答案是否定的。
早在Java1.2推出之時,Java平台中就引入了一個新的支持:java.lang.ThreadLocal,給我們在編寫多線程程序時提供了 一種新的選擇。ThreadLocal是什么呢?其實ThreadLocal並非是一個線程的本地實現版本,它並不是一個Thread,而是thread local variable(線程局部變量)。也許把它命名為ThreadLocalVar更加合適。線程局部變量(ThreadLocal)其實的功用非常簡單, 就是為每一個使用某變量的線程都提供一個該變量值的副本,是每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本沖突。從線程的角度看,就好像 每一個線程都完全擁有一個該變量。
ThreadLocal是如何做到為每一個線程維護變量的副本的呢?其實實現的思路很簡單,在ThreadLocal類中有一個Map,用於存儲每一個線程的變量的副本。
比如下面的示例實現(為了簡單,沒有考慮集合的泛型):
1 public class ThreadLocal { 2 private Map values = Collections.synchronizedMap(new HashMap()); 3 public Object get() { 4 Thread currentThread = Thread.currentThread(); 5 Object result = values.get(currentThread); 6 if(result == null&&!values.containsKey(currentThread)) { 7 result = initialValue(); 8 values.put(currentThread, result); 9 } 10 return result; 11 } 12 public void set(Object newValue) { 13 values.put(Thread.currentThread(), newValue); 14 } 15 public Object initialValue() { 16 return null; 17 } 18 }
那麽具體如何利用ThreadLocal來管理Session呢?Hibernate官方文檔手冊的示例之中,提供了一個通過ThreadLocal維護Session的好榜樣:
1 public class HibernateUtil { 2 public static final SessionFactory sessionFactory; 3 static { 4 try { 5 sessionFactory = new Configuration().configure().buildSessionFactory(); 6 } catch (Throwable ex) { 7 throw new ExceptionInInitializerError(ex); 8 } 9 } 10 public static final ThreadLocal<Session>session=new ThreadLocal<Session>(); 11 public static Session currentSession() throws HibernateException { 12 Session s = session.get(); 13 if(s == null) { 14 s = sessionFactory.openSession(); 15 session.set(s); 16 } 17 return s; 18 } 19 public static void closeSession() throws HibernateException { 20 Session s = session.get(); 21 if(s != null) { 22 s.close(); 23 } 24 session.set(null); 25 } 26 }
只要借助上面的工具類獲取Session實例,我們就可以實現線程范圍內的Session共享,從而避免了線程中頻繁的創建和銷毀Session實例。當 然,不要忘記在用完后關閉Session。寫到這里,想再多說一些,也許大多數時候我們的DAO並不會涉及到多線程的情形,比如我們不會將DAO的代碼寫 在Servlet之中,那樣不是良好的設計,我自己通常會在service層的代碼里訪問DAO的方法。但是我還是建議采用以上的工具類來管理 Session,畢竟我們不能僅僅考慮今天為自己做什么,還應該考慮明天為自己做什么!