Hibernate的线程
前提:由于后面学习的整合框架spring,是不能使用new 对象。所以不能使用构造函数传递session给DAO
想法:我们希望在DAO里面获得的Session对象和外层获得的Session的是同一个对象。不使用参数从外层调用方传递到DAO。
- 如何实现外层的session和DAO的session是同一个对象?
- 答:可以使用线程绑定。意思就是同一条线程的session对象是相同的。
线程绑定的作用:就是让同一条线程获得session对象是相同的,不需要参数传递session!!!!
所谓的线程绑定,就是使用一个线程变量将对象ThreadLoad保存起来,保证同一条线程获得同一个对象
所谓的绑定Session到当前线程,就是同一条线程的操作,session是相同的
实现的方式有两种:
- Hibernate的内置实现
- 自定义的ThreadLoad的线程变量实现。
不能同时配置
hibernate的内置实现
如果使用hibernate的内置实现要注意的事项:
1. session不能手动关闭
- session绑定到当前线程。会随线程启动而启动。随线程结束而结束。不能手工关闭
2. 所有的操作都要打开事务,包括查询(原来查询是不需要启动事务的)
- 配置了线程绑定,HIbernate就要验证事务激活状态,导致了所有的操作都要开启事务,包括查询!!
hibernate内置实现步骤:
- 配置文件配置
<!-- 绑定线程 -->
<property name="hibernate.current_session_context_class">thread</property>
- 修改SessionFactory获得Session的代码,使用getCurrentSession()方法
//2.获得Session
public static Session getSession(){
//前提是配置了sesion绑定当前线程
//获得当前线程的session对象
return sessionFactory.getCurrentSession();
}
内置实现后session不能手动关闭
@Test
public void save() {
//如果外层的session和里面不一样,导致无法提交事务。
//如果在不能使用参数将外层的session传递个DAO。要解决外层很DAO里面的session相同。
//只能将session绑定到当前线程。只有在当前线程。我们获得的session是相同的
Session session = HibernateUtils.getSession();
System.out.println(session.hashCode()+"---");
Transaction transaction = session.beginTransaction();
CustomerDAO dao = new CustomerDAO();
Customer c = new Customer();
c.setCustName("百度");
dao.save(c);
transaction.commit();
//如果session绑定到当前线程。会随线程启动而启动。随线程结束而结束。不能手工关闭
//session.close();
}
所有的操作都要打开事务,包括查询(原来查询是不需要启动事务的)
@Test
public void get(){
try {
Session session = HibernateUtils.getSession();
//如果使用了线程绑定,操作必须要启动事务。包括查询
session.beginTransaction();
Customer customer = session.get(Customer.class, 5L);
System.out.println(customer.getCustName());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
使用ThreadLoad自定义实现
- 修改SessionFactory获得Session的代码,使用openSession()方法
使用ThreadLocal不用担心查询操作也要开启事务
修改工具类
public class HibernateUtils {
public static final SessionFactory sessionFactory=HibernateUtils.createSessionFactory();
//1.声明一个线程变量对象,所谓的线程变量,就是如果放在该变量里面的对象可以保持同一条线程共享。
//2.如果将session放在threadLocal对象里面就可以实现同一条线程共享
private static ThreadLocal<Session> threadLocal=new ThreadLocal<Session>();
//获得会话工厂
private static SessionFactory createSessionFactory(){
//1.获得配置类对象Configuration
Configuration config=new Configuration();
//2.读取默认的配置文件(classpath:hibernate.cfg.xml)
config.configure();
//3.构建会话工厂
SessionFactory sessionFactory = config.buildSessionFactory();
return sessionFactory;
}
//2.获得一个会话,操作对象,通过threadLocal获得
public static Session getSession(){
//如果threadLocal没有值,那么就创建一个session对象放到里面
if(threadLocal.get()==null){
Session session = sessionFactory.openSession();
threadLocal.set(session);
}
//如果threadLocal已经有对象了,就直接返回该session对象
return threadLocal.get();
}
//注意:如果使用自定义的threadLocal绑定session到当前线程。直接使用session关闭了数据库连接,threadLocal里面的
//session对象还在。就会导致下次获得的session的对象无法连接数据库。
//所以,关闭了session还需要移除threadLocal里面的session
public static void close(){
//判断线程变量里面是否有session对象
if(threadLocal.get()!=null){
//如果有就获得session对象
Session session = threadLocal.get();
//关闭session对象
session.close();
//移除session对象
threadLocal.remove();
}
}