书上有一个工具类 HibernateUtil,书本解释它的作用是:
“将Hibernate Session 存放在一个ThreadLocal变量中,对于同一个线程的请求,将可以轻松访问该Session”
“可以保证将线程不安全的Session绑定限制在当前线程内——也就是实现‘上下文相关的’Session”我不明白的是—— 既然从 SessionFactory.openSession() 获取 Session 不是单例模式,也就是每次获取 Session都是不同的,那么为什么会出现 多个线程同时访问同一个Session的问题呢?比如,在一个Web应用中,在处理用户请求的Servlet中通过 SessionFactory.openSession() 获取一个Session,然后访问数据库,最后关闭Session,按理说每次用户请求所用到的 Session 应该是不同的,应该不会出现多个线程同时访问同一个Session造成的线程安全问题啊,为什么要用工具类 HibernateUtil呢??不解~~恳求各位高手慷慨解惑,万分感激!!!
解决方案 »
- 发送邮件,被QQ定义为疑似垃圾邮件,怎么解决这个问题?
- 数据库有数据resultset.next()却是false,急急啊
- 生产系统:acegi+ladp做的用户权限验证,登陆时线程堵塞
- 项目中使用了hibernate注解,可实现功能的时候报找不到hibernate注解
- apache 怎么连接 tomcat
- 怎么将.WAR文件部署到tomcat中
- 散分,庆祝转向JAVA开发
- 一外包项目,根据需求,如何设计数据库中的表、字段及个表之间关联关系????设计得好还可加分!!!
- 请教:读取配置文件问题
- jb的ejb例子中各个HOME类中几个JAVA文件是怎么产生的
- struts2有没有什么方式主动响应到页面?
- 关于基于J2EE电子地图服务系统的问题
====================================================================================
谢谢fpy_061625的夸奖,对于编程其实我只是个菜鸟,很惭愧!我只是觉得:搞编程,学任何一门技术、工具(比如Hibernate),理解其实现原理、思想是最重要的,反而语法、配置、操作是其次——当你理解了其实现原理、思想,就不会被它那些纷繁复杂的配置、操作所迷惑。理解了就不会觉得它很神秘:“哦,这种设计如果让我来搞,也许我也会这样想”,还有可能发现它的不足从而改进它,甚至有必要时自己开发一套更加先进的工具;反之如果不理解,即使对语法、配置、操作烂熟于心,它都不是你的,人家工具怎么改怎么变,你只能跟着走,自己没有任何主动权。我本身是读数学的,也许还带着这样一种习惯 —— 面对一大堆纷繁复杂的抽象符号、式子、数字、曲线,如果你头脑中对其背后的思路、原理有个很清晰的概念,就永远不会被它疑惑,否则见到就头疼。第一次发帖提问,希望高手们可以多多指教,感激不尽!当人也希望结识有相同兴趣、志向的朋友。
对于SessionFactory.openSession() 来说,同一个线程内不管做多少次
session1=SessionFactory.openSession() ;
session2=SessionFactory.openSession() ;
session1=session2;
创建的session都是相等的,这样保证了session内操作数据的完整性和隔离性。
反之则不相当
对于SessionFactory.openSession() 来说,同一个线程内不管做多少次
session1=SessionFactory.openSession() ;
session2=SessionFactory.openSession() ;
session1=session2;
创建的session都是相等的,这样保证了session内操作数据的完整性和隔离性。
反之则不相当
===================================================================================
谢谢回复!
但是我尝试过,在这种情况下执行 System.out.println(session1==session2),
结果等于false, 说明两次获取的session是不同的。而且我的意思是:想看看有什么情况会出现多个线程同时共享一个session问题,因为我想搞明白那个工具类HibernateUtil的存在究竟有什么意义,目前我想不到任何一定要用到它的例子。
谢谢推荐!但我粗略看了一下,那帖子是介绍怎样实现保证“一个线程上最多只能创建一个session实例 .并且每个线程都能创建一个实例”的问题,没有提到怎样会出现多个线程同时访问一个session的问题。
首先非常感谢fudoublelong朋友的回复!“把session声明为servlet的实例变量,就会出现多个线程访问一个session 的情况”——
这个很容易理解,这样相当于多个线程同时访问同一个Servlet实例,那么当然也共享它的成员变量(属性)session,毫无疑问。但问题是为什么要这样做?为什么不把session声明为Servlet方法的局部变量(此时相当于要用session实例时就创建、用完就关闭、销毁)? 这样做不是很方便且节省内存吗??会有什么负面作用??(好像创建session实例代价开销不大)盼指教!
主要是为了“‘上下文相关的’Session”
也就是说,使用Threadlocal对当前进程进行判断,
如果是有[这个线程的session]就直接返回。而lz担心的“多个线程”,可能就有了多了session了。随便胡说一下,
等待被拍砖bdgood luck
谢谢回复!大家交流,不存在什么“胡说”,只要多交流即使没有最终的结果,都会有收回的。
但可能你误解了我的疑问,我不是对ThreadLocal的作用有什么怀疑。
这样就会出错了。
谢谢您的回复!
上面12楼的朋友也提到您所说的这个问题,但我还是有疑问——为什么要将session设置为Servlet的实例变量?为什么不把session声明为Servlet方法的局部变量(此时相当于要用session实例时就创建、用完就关闭、销毁)? 这样做既可避免发生多个线程同时访问一个Session带来的线程安全问题,也很方便,又节省内存,会有什么负面作用吗??(好像创建session实例的代价、开销不大)
谢谢回复!
但我的疑问不是ThreadLocal作用的问题。
我的疑问是为什么会出现多个线程同时访问同一个Session的情况,如果可以简单地避免这种情况(比如像我所说的把Session声明为局部变量,要用就建,用完立刻销毁,根本不会出现多线程访问冲突),又没什么负面作用的,那么要这个ThreadLocal有什么用??
当然是false的,这个是基本概念里的了,两个对象的相等判断,你这样肯定是false
先不说他们是否是一个session,就算是,那也只能说是两个不同的引用,指向同一个session对象了,本身session1 和 session2是两个不同的对象
对于ThreadLocal的作用,我觉得只是为了避免一个线程中过于频繁的openSession和closeSession,在Web应用中,可以在filter中统一管理。
而如果你每次在访问时都打开新的Hibernate的Session,那么事务等都不方便进行处理。所以很多时采用的是每一次Http请求只打开一个Hibernate的Session及事务。使用ThreadLocal就可以做到这一点
(好像创建session实例的代价、开销不大)//创建session的开销在高并发情况下是很大的。而用thread可以解决这个问题:
“将Hibernate Session 存放在一个ThreadLocal变量中,对于同一个线程的请求,将可以轻松访问该Session”
当同一个线程再次请求时,只需从threadlocal中获取 而无需再创建。
我感觉您是理解了lz的问题了,
可是您回答的还是拐到了“为什么使用ThreadLocal”上。
也不是lz的核心问题-“会不会有情况遇到多线程冲突”和“什么情况下会遇到”占地学习bdgood luck
估计lz就是要看这句“原本根本就不存在“多线程访问冲突”的问题。” 我寒是因为...现在是冬天。
...哈哈good luck
感谢回复!
您的回答对我很有启发意义,我有点理解ThreadLocal在此处的意义了,不错!!
感谢回复!
您的回答对我也很有用!我明白了Threadlocal的意义了,不会再纠缠于“会否有多线程并发一个session的问题”。
感谢回复!
我对您的回答感到非常满意!!
您已经很理解我的疑惑,got the point! 并且回答得很详细、很到位,我明白这个ThreadLocal 的作用了,再次感谢!还有几个相关的问题想请教,
(1)session.beginTransaction()、session.commit()是不是通知数据库执行一次相应的“开启事务”和“提交事务”的指令??因为据我所知道,应用程序事务和数据库事务并不一定是一 一对应的
(2)如果(1)的答案是肯定的话,那么session.beginTransaction()、session.commit()之间的代码(执行时间)应该尽可能地短,否则会阻止数据库的并发修改从而影响网站性能,对吗?
(3)在一个线程中,每次要用到 ThreadLocal中的Session的时候,都应该是:开启事务--> 持久化操作-->提交事务,而无须每次都关闭Session,Session留待最后一次用完后才关闭,对吗??
若能回答,感激不尽!!
我今天也是对多线程,单实例疑惑,上面这个是我个人看法,望各位给指导指导。
那就是说明了每对对象访问的时候为其出创建了一个session的副本,所以会不相等
但是都是同一个对象的副本
不用显示地在本次请求中传递session,简化代码。而不是为了控制多线程问题。sf好像还有个方法叫xxxxCurrentSession(),可以返回不同的session。
ThreadLocal的使用就是在单例的情况下如何保存各线程中保存的变量值
至于你说的openSession()每次获取到的对象都是不一样的,你的理解是对的,的确不一样的
1、HibernateUtil是帮助你获得与线程上下文相关的Session,Session的这个特性我个人概括为线程敏感性,即每个Session一般都是和一个具体的线程相关的,是线程敏感的,这是Session的一个重要特性,为什么要强调线程敏感呢?或者说程序中什么为什么需要和当前线程上下文相关的那个Session呢?是因为Session是承载事物的一个载体,一般都是通过Session来创建一个Transaction,而Transcation创建的位置有的时候需要跨DAO层,例如银行转账业务,有一个DAO对象叫Deposit.java表示存款操作,还有一个DAO对象叫Withdraw.java,即取款对象,由于转账需要同时调用两个操作,因此事物应该在业务逻辑层开启,于是,在每个DAO对象的代码中就存在如何获得在业务层已经获取到的那个事物的代码,这个时候就需要Session.getcurrent方法,于是你就得到了和这个线程相关的Session,而这个session是在业务逻辑层开启的,它可以被下面涵盖的多个DAO操作通过ThreadLocal方式来共享,HibernateUtil在Hibernate3中已经不用了,因为早期的Hibernate是不提供getcurrent方法来获得线程敏感的Session的,后来Hibernate3了,这个功能就加上了。呵呵。上次回答的时候没有注意,没看清楚问题,今天仔细又看了一下楼主的问题,希望你可以明了。你现在的问题是不要将HibernateUtil类的功能与所谓的“多个线程为什么要访问同一个Session”这样的问题联系起来呢,这两个东西本来就没有关系,人家建立HibernateUtil也不是为了这个,呵呵。2、Session除了线程敏感特性以外,还包括线程非安全性。如何理解Session的线程非安全性?其实很简单,由于每个线程都有自己的上下文的Session,而Session类自身的方法是不提供资源访问方面的同步性的,因此Session不是线程安全的,因此在有些时候,通过Session来访问数据库的时候要考虑并发的问题,而并发可以通过什么机制来控制呢?当然是锁!乐观锁、悲观锁等等而锁控制的你读完之后谁能写,但有这个还不够,有的时候你还需要控制“你写完之后谁能读”,这是怎么实现的呢?当然是事务隔离级别,即所谓的提交读,为提交读,重复读等等。以上内容不知道对楼主整理思路是否有帮助,呵呵。
设计的初衷:提高性能
设计陈述:
1)尽量只访问内存不访问硬盘(不访问硬盘是不可能的,这里指减少次数)
2)Session一个轻量级对象,它对性能的贡献并不是很大,所以它的另外一个作用应该就是要保证一个事务的正常完成(当事务2发现Session的缓存a被事务1占用中,它应该要new一个Session的缓存b来供给事务2;相反,当事务2发现Session的缓存a空闲,那就应该直接占用它。这是由事务的原子性决定的,所以你设计的Session也应该尽量遵循它,把它的错误限定在事务本身内部)