connection、HttpSession、hibernate中的session、transaction

来源:互联网 发布:李拉大提琴知乎 编辑:程序博客网 时间:2024/05/20 18:55

connection和HttpSession的区别

session(会话)和connection(连接)的定义:
connection
:是一个物理的概念,它指的是一个通过网络建立的客户端和专有服务器(Dedicated Server)或共享服务器(Shared Server)的一个网络连接,既是一条物理路劲。

session:是一个逻辑的概念,它是存在于实例中,一个连接可以拥有多个会话也可以没有会话,同一个连接上的不同会话之间不会相互影响。

有A/B两个城市,需要从A运送白菜到B城 


我们先建设一条公路 
然后运送白菜过去,包括准备白菜和运送白菜以及返回等一系列的动作。 

一条公路,可以运送0-n次的白菜 
当然从A到B的公路也可能不只一条。 
某一次运送白菜,可以在真正上路时才开通某一条道路 
一次运送不会影响别的运送的状态 


对应数据库 
A代表客户端进程 
B代表服务器端进程 
公路代表连接, 
运送一次白菜代表一个会话 

一个连接可以进行多次的会话 
一个会话可以不依赖于某个连接,甚至没有连接(当我准备好了,真正开始运送时再建立连接) 

一个会话不会影响别的会话



ThreadLocalSessionContext的名称上看,它所做的就是把一个session绑定到当前线程上,让当前线程作为session的上下文。这样,在service里不同的dao通过sessionFactory.getCurrentSession()得到的将是当前线程上的同一个session,这是非常必要的做法,通过使用同一个session确保了持久化对象的一致性。但是从
ThreadLocalSessionContext的代码来看,它并只是做了这一件事,它还做了另外一件非常“醒目”的事情:即给session包裹了一层代理org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper,这个代理将拦截session的操作,对session的使用做出了如下的限制:

1.在没有显式地开始一个事务之前,不能使用session的任何数据访问方法。

2.一旦事务提交,session将自动close。

参考:http://www.xuebuyuan.com/1587708.html


Session是JAVA应用程序和Hibernate进行交互时使用的主要接口,它也是持久化操作核心API,Session对象是有生命周期的,它以Transaction对象的事务开始和结束边界 。Session作为贯穿Hibernate的持久化管理器核心,提供了众多的持久化的方法,如save(), update ,delete ,find(Hibernate 3中已经取消了此方法)等,通过这些方法我们可以透明的完成对象的增删改查。

SessionFactory负责创建Session,SessionFactory是线程安全的,多个并发线程可以同时访问一个SessionFactory 并从中获取Session实例。而Session并非线程安全,也就是说,如果多个线程同时使用一个Session实例进行数据存取,则将会导致Session 数据存取逻辑混乱.因此创建的Session实例必须在本地存取空上运行,使之总与当前的线程相关。

Session有以下的特点
  1,不是线程安全的,应该避免多个线程共享同一个Session实例 
  2,Session实例是轻量级的,所谓轻量级:是指他的创建和删除不需要消耗太多资源 
  3,Session对象内部有一个缓存,被称为Hibernate第一缓存,他存放被当前工作单元中加载的对象,每个Session实例都有自己的缓存。

Hibernate Session缓存被称为Hibernate的第一级缓存。SessionFactory的外置缓存称为Hibernate的二级缓存。
这两个缓存都位于持久层,它们存放的都是数据库数据的拷贝。SessionFactory的内置缓存存放元数据和预定义SQL, SessionFactory的内置缓存是只读缓存。

Hibernate Session缓存的三大作用
1,减少数据库的访问频率,提高访问性能。
2,保证缓存中的对象与数据库同步,位于缓存中的对象称为持久化对象。
3,当持久化对象之间存在关联时,Session 保证不出现对象图的死锁。

Session 如何判断持久化对象的状态的改变呢?
Session 加载对象后会为对象值类型的属性复制一份快照。当Session 清理缓存时,比较当前对象和它的快照就可以知道那些属性发生了变化。

Session 什么时候清理缓存?
1,commit() 方法被调用时
2,查询时会清理缓存,保证查询结果能反映对象的最新状态。
3,显示的调用session 的 flush方法。
session 清理缓存的特例:
当对象使用 native 生成器时会立刻清理缓存向数据库中插入记录。
public class HibernateUtil {public static final SessionFactory sessionFactory;public static final ThreadLocal<Session> session = new ThreadLocal<Session>();static {try {Configuration configuration = new Configuration().configure();sessionFactory = configuration.buildSessionFactory();} catch (Throwable ex) {System.err.println("Initial SessionFactory creation failed." + ex);throw new ExceptionInInitializerError(ex);}}public static Session currentSession() throws HibernateException {Session s = (Session) session.get();if (s == null) {s = sessionFactory.openSession();session.set(s);}return s;}public static void closeSession() throws HibernateException {Session s = (Session) session.get();if (s != null)s.close();session.set(null);}}


通过以上代码(ThreadLocal<Session>),我们就可以实现线程范围内的Session共享,从而避免了在线程中频繁的创建和销毁Session 实例。不过注意在线程结束时关闭Session。同时值得一提的是,新版本的Hibernate在处理Session的时候已经内置了延迟加载机制,只有在真正发生数据库操作的时候,才会从数据库连接池获取数据库连接,我们不必过于担心Session的共享会导致整个线程生命周期内数据库

Hibernate Transaction是从Session中获得的,tx = session.beginTransaction(),最后要先提交tx,然后再session.close,这完全符合JDBC的Transaction的操作顺序,但是这个顺序是和JTA的Transactioin操作顺序彻底矛盾的!!! JTA是先启动Transaction,然后启动Session,关闭Session,最后提交Transaction,因此当你使用JTA的Transaction的时候,那么就千万不要使用Hibernate的Transaction


总结: 

1、在JDBC上使用Hibernate 

必须写上Hibernate Transaction代码,否则数据库没有反应。此时Hibernate的Transaction就是Connection.commit而已 

2、在JTA上使用Hibernate 

写JTA的Transaction代码,不要写Hibernate的Transaction代码,否则程序会报错 

3、在EJB上使用Hibernate 

什么Transactioin代码都不要写,在EJB的部署描述符里面配置 
Java代码  
|---CMT(Container Managed Transaction);   
|   
|---BMT(Bean Managed Transaction);   
        |   
        |----JDBC Transaction   
        |   
        |----JTA Transaction   

你说“Hibernate的JDBCTransaction根本就是conn.commit而已,根本毫无神秘可言,只不过在Hibernate中,Session打开的时候,就会自动conn.setAutoCommit(false),不像一般的JDBC,默认都是true,所以你最后不写commit也没有关系,由于Hibernate已经把AutoCommit给关掉了,所以用Hibernate的时候,你在程序中不写Transaction的话,数据库根本就没有反应” 
但sf.opengSession()时,并没有setAutoCommit(false),我想问的是,如果不编写任何事务代码,如: 
Java代码  
Session s = sf.openSession();;   
......   
s.close();;  
数据库会不会有反应(此时应该是默认AutoCommit为true)。 

另外,我想问一下: 
1. s.flush()是不是必须的 
2. s.close()是不是一定要关闭 
比如你上面提到的: 
Java代码  
javax.transaction.UserTransaction tx = new InitialContext();.lookup("javax.transaction.UserTransaction");;    
Session s1 = sf.openSession();;    
...    
s1.flush();;    
s1.close();;    
..
Session s2 = sf.openSession();;    
...    
s2.flush();;    
s2.close();;    
tx.commit();;  
s1不关闭,使用s2进行操作的代码中使用s1可不可以(我觉得这样更加节约资源,不需要反复的连接、关闭)

引用
但sf.opengSession()时,并没有setAutoCommit(false),我想问的是,如果不编写任何事务代码,如: 
Session s = sf.openSession(); 
...... 
s.close(); 
数据库会不会有反应(此时应该是默认AutoCommit为true)。
不会有反应。在sf.openSession() 创建Session实例的时候,就已经调用了conn.setAutoCommit(false)了。

详情请参考:Hibernate Session & Transaction详解





1 0