原理:基于threadLocal:
使用hibernate,我们最终要获得的是一个hibernate session对象,
在第一次使用到一个hibernate Session的时候,创建创建一个session,并将其存储到threadLocal map集合中。
在同一个请求中,如果我们还需要用到这个session.我们就可以从threadLocal map集合中获取到这个session.接着使用。
在请求结束时(可以使用filter),关闭并清除ThreadLocal Map 中的所有session对象。
优点:可以配置多个数据源;可以在一个请求中在任何地方获取到hibernate session 对象;无需手工关闭hibernate session对象。
缺点:hibernate session 存活时间较长;我没详细测试过,只是理论上可行。
下面是代码:
1 HSessionHolder.java:用于获取到对应的session.
package com.hf.hibernate.util;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
/**
*
* @author Administrator
*
*/
public class HSessionHolder {
private static Logger logger = Logger.getLogger(HSessionHolder.class);
/**
* threadLocal集合,对应了不同的配置文件
*/
private static Map <String ,ThreadLocal<Session>> threadLocalMap =new HashMap <String ,ThreadLocal<Session>>();
/**
* 配置文件名称-路径集合
*/
private static Map <String ,String> configFileLocationMap =new HashMap <String ,String>();
/**
* Hibernate SessionFactory 名称-对象集合
*/
private static Map <String ,SessionFactory> sessionFactoryMap =new HashMap <String ,SessionFactory>();
/**
* hibernate配置文件读取器
*/
private static final Configuration cfg = new Configuration();
/**
*
*/
private static final String DEFAULT_FLAG = "configOne";
/**
* 初始化配置文件集合
*/
static {
/**
* 初始化配置文件集合
*/
String configOneFlag="configOne";
String configOnePath="/com/hf/hibernate/config/hibernate.cfg.xml";
configFileLocationMap.put(configOneFlag,configOnePath);
/**
* 初始化threadLocalMap集合
*/
ThreadLocal<Session> configOneT = new ThreadLocal<Session>();
threadLocalMap.put(configOneFlag,configOneT);
/**
* 初始化各个sessionFactory对象
*/
Iterator configIterator =configFileLocationMap.keySet().iterator();
while(configIterator.hasNext()){
String configFlag = (String) configIterator.next();
String configPath = configFileLocationMap.get(configOneFlag);
cfg.configure(configPath);
SessionFactory sessionFactory = cfg.buildSessionFactory();
sessionFactoryMap.put(configFlag, sessionFactory);
}
}//static
/**
* 获取默认数据库的会话对象
* @param flag
* @return
*/
public static Session getSession() {
String flag= DEFAULT_FLAG;
return getSession(flag);
}
/**
* 关闭所有可能已经打开的hibernate会话
* @return
*/
public static void closeSessions() {
/**
* 遍历所有的threadLocalMap的成员,如果存在Session,则关掉。
*/
Iterator<String> threadLocalIterator =threadLocalMap.keySet().iterator();
while(threadLocalIterator.hasNext()){
ThreadLocal<Session> t =threadLocalMap.get(threadLocalIterator.next());
Session session = t.get();
if(session!=null){
session.close();
t.set(null);
logger.info("成功的关闭了一个hibernate Session,并清空ThreadLocal");
}
}
}
/**
* 获取制定数据库的会话对象
* @param flag
* @return
*/
public static Session getSession(String flag) {
/**
* 取到threadLocal
*/
ThreadLocal<Session> t = threadLocalMap.get(flag);
if(t==null){
try {
throw new Exception("无效的threadlocal 标志");
} catch (Exception e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
return null;
}
/**
* 看看里面是不是已经有session了
*/
Session session = (Session) threadLocalMap.get(flag).get();
/**
* 没有的话创建一个新的
*/
if (session == null || !session.isOpen()) {
SessionFactory sessionFactory = sessionFactoryMap.get(flag);
if (sessionFactory != null) {
session = sessionFactory.openSession();
}
/**
* 将session存入threadLocal
*/
t.set(session);
}
return session;
}
}
2 filter:HSessionFilter :在结束时关闭所有打开的hibernate session
package com.hf.hibernate.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hf.hibernate.util.HSessionHolder;
public class HSessionFilter implements Filter {
private static final Log log = LogFactory .getLog(HSessionFilter.class);
public void init(FilterConfig config) throws ServletException {
}
/**
* 此过滤器只在最终关闭掉所有打开的session就可以了。
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} finally {
HSessionHolder.closeSessions();
}
}
public void destroy() {}
}
使用方法:
例如在一个DAO的保存方法中:
/**
* 保存信息分类对象到数据库中,已经设置好了id了
* @return
*/
public static boolean save(Info category) {
log.info("开始进行保存分类信息操作");
/*获取到hibernate session,这里调用的是默认的数据库配置*/
Session session = HSessionHolder.getSession();
/*开启事务*/
Transaction tran = session.beginTransaction();
try {
session.save(category);
tran.commit();
} catch (Exception e) {
//这里应该增加回退功能
e.printStackTrace();
return false;
}
return true;
}