java web 解析ThreadLocal在持久层中的应用

应用背景:

我们知道java web项目开发中不可避免的是连接数据库,这里我们设定数据库的连接及其对数据库的查询、更新、修改为持久层的操作。我们在web项目开发中对持久层操作不可缺少的利器是Hibernate。对于hibernate是什么、背景楼主就不一一解释了。好的!让我们进入主题:

Hibernate里的Session为org.hibernate.Session,代表一次完整的数据库操作,与servlet里的Session完全不同。一次Session操作可以包括多次的数据库的读写、多个事务。我们知道Session是由SessionFactory负责创建的,而多个并发的线程可以同时访问一个SessionFactory并从中获取Session实例,那么Session是非线程安全的,由此背景我们引入了ThreadLocal。

 

1.ThreadLocal是什么?原理?

其实ThreadLocal并不是一个Thread,而是thread local variable(线程局部变量)。

在运用中为避免资源消耗,一般都会手动封装一个HibernateUtil类(未使用Spring管理的前提下)。该类的作用使Hibernate加载配置文件config, 创建sessionFactory等只运行一次。
实际运用中,经常需要将当前线程和session绑定.一般的用法为使用ThreadLocal:在HibernateUtil类中封装hibernate的管理。通过openSession取得session,并将其放入ThreadLocal变量中。这样业务逻辑中仅需通过工具类取得当前线程对应的session。使用完毕后,调用工具类closeSession方法将session关闭,当前线程的ThreadLocal变量置为NULL。保证线程归还线程池复用后,ThreadLocal为空,以免出现导致其他线程访问到本线程变量。
而后,Hibernate的SessionFactory提供获取session的新方法getCurrentSession (获得与当前线程绑定的session)。内部通过代理封装,此方式得到的session不仅和当前线程绑定,也无需手动开关。默认在事务提交之后,session自动关闭。需注意的是,必须在事务开启的前提之下才可使用此种方式获得的session。此外hibernate.cfg.xml配置文件中也需配置

<propertyname="current_session_context_class">thread</property>

最后,引入Spring之后。sessionfactory的创建等都交给spring管理。Spring也提供了HibernateTemplate,HibernateDaoSupport这样的封装方法。用户可以不再考虑session的管理,事务的开启关闭。只需配置事务即可。而所谓session关闭后,因延迟加载导致前台无法显示的问题以往解决方式为强制全部加载,现在也可通过在web.xml中配置org.springframework.orm.hibernate3.support.OpenSessionInViewFilter来解决。

总的来讲就是给session加了一把锁机制,防止并发访问时出现错误。

{ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new对象的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。通过ThreadLocal.set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行ThreadLocal.get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。}这个是别人的观点!!!//倒数第二个图标去除背景,汗!!!


2. ThreadLocal管理hibernateSession实例


HibernateUtil类:

package com.jc.util;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
	// 声明SessionFactory对象
		private static SessionFactory factory = null;
		// 实例化ThreadLocal对象
		private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
		// 实例化Configuration对象
		private static Configuration cfg = new Configuration();
		// 静态块
		static {
			try {
				// 加载Hibernate配置文件
				cfg.configure();
				// 实例化SessionFactory
				factory = cfg.buildSessionFactory();
			} catch (HibernateException e) {
				e.printStackTrace(); // 打印异常信息
			}
		}

		/**
		 * 获取Session对象
		 * @return Session对象
		 */
		public static Session getSession() {
			// 从threadLocal中获取Session
			Session session = (Session) threadLocal.get();
			// 判断session是否为空或未处于开启状态
			if (session == null || !session.isOpen()) {
				if (factory == null) {
					rebuildSessionFactory();
				}
				// 从factory开启一个Session
				session = (factory != null) ? factory.openSession() : null;
				threadLocal.set(session); // 将session放入threadLocal中
			}
			return session;
		}

		/**
		 * 获取SessionFactory对象
		 * @return SessionFactory对象
		 */
		public static SessionFactory getSessionFactory() {
			return factory;
		}

		/**
		 * 关闭Session
		 * @param session对象
		 */
		public static void closeSession() {
			// 从threadLocal中获取Session
			Session session = (Session) threadLocal.get();
			// 移除threadLocal中的对象
			threadLocal.remove();
			if (session != null) {
				if (session.isOpen()) {
					session.close(); // 关闭Session
				}
			}
		}

		/**
		 * 创建SessionFactory对象
		 */
		public static void rebuildSessionFactory() {
			try {
				// 加载Hibernate配置文件
				cfg.configure();
				// 实例化SessionFactory
				factory = cfg.buildSessionFactory();
			} catch (Exception e) {
				e.printStackTrace(); // 打印异常信息
			}
		}
}


Dao层包:

import org.hibernate.Query;
import org.hibernate.Session;

import com.jc.model.User;
import com.jc.util.HibernateUtil;

/**
 * 用户数据库处理类
 */
public class UserDao {
	/**
	 * 保存用户
	 * @param user User对象
	 */
	public void saveUser(User user){
		Session session = null;					//Session对象	
		try {
			//获取Session
			session = HibernateUtil.getSession();
			session.beginTransaction();			//开启事物
			session.save(user);					//持久化user
			session.getTransaction().commit(); 	//提交事物
		} catch (Exception e) {
			e.printStackTrace();				//打印异常信息
			session.getTransaction().rollback();//回滚事物
		}finally{
			HibernateUtil.closeSession();		//关闭Session
		}
	}
}


这里线程A首先使用Dao包中的UserDao类 session = HibernateUtil.getSession();将会执行HibernateUtil类中static块创建一个factory,之后执行里面的getSession()方法,当session = (factory != null) ? factory.openSession() : null;语句执行完后,session打开。之后的threadLocal.set(session);会将session保存到threadLocal里。

之后来了线程B,同样使用Dao包中的UserDao类 session = HibernateUtil.getSession();但是在执行到getsession()里面时,我们会发现通过Session session = (Session) threadLocal.get();获得的session是非空的,之后if (session == null || !session.isOpen())两个条件均不成立(A正在使用),故里面语句不执行,session并发访问控制得到很好解决,谢谢阅读!


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值