调试 Hibernate“会话已关闭!” - 滥用SSB?
(首先,这不是我的代码。其次,为了保护有罪者,我更改了类名称以隐藏特定于我的雇主的任何内容,因此如果事情彼此不一致,这就是原因!)。
有人可以帮我解答疑问吗?我被要求调查完整连接池的问题,而这段代码似乎有味道。
我们的日志中有很多 org.hibernate.SessionException: Session is close! ,围绕以下代码,该代码使用了表现不佳的连接池。
调用通过 Web 服务传入:
1 @Stateless
2 @WebService(name="MyWebService", targetNamespace="http://www.mycompany.com/2010/01/WebService/myWebService")
3 @WebContext(contextRoot="/myContextRoot", secureWSDLAccess=false)
4 public class MyWebService implements IMyWebService {
6 @WebMethod
7 @NotNull
8 public ArrayList<SearchResult> performSearch(ArrayList<String> criteria) {
9 GetAllResponses caller = new GetAllResponses();
10 return caller.doSearch(criteria);
11 }
13 }
GetAllResponses
类如下:
1 public class GetAllResponses {
2 private static MyHome myHome = new MyHome();
4 public SearchResult doSearch(ArrayList<String> criteria) {
5 return doSearchInternal(criteria.elementAt(0), criteria.elementAt(1));
6 }
8 private SearchResult doSearchInternal(String a, String b) {
9 DataObject info = myHome.findDataObject(a, b);
10 return info.getAsSearchResult();
11 }
12 }
MyHome
如下:
1 @Stateless
2 @Local({MyHomeInterface.class})
3 public class MyHome {
4 private Session session;
6 public DataObject findDataObject(String a, String b) {
7 try {
8 this.session = MyHibernateUtil.getSessionFactory().getCurrentSession();
9 Transaction tx = this.session.beginTransaction();
10 //do stuff with session and return a DataObject
11 } catch (Exception ex) {
12 ex.printStackTrace();
13 } finally {
14 this.session.close();
15 }
16 }
18 public DataObject doAnotherFind(String a, String b) {
19 try {
20 this.session = MyHibernateUtil.getSessionFactory().getCurrentSession();
21 Transaction tx = this.session.beginTransaction();
22 //do stuff with session and return a DataObject
23 } catch (Exception ex) {
24 ex.printStackTrace();
25 } finally {
26 this.session.close();
27 }
28 }
30 }
请注意 GetAllResponses
第 2 行的情况MyHome
类被实例化为静态字段,并且在 MyHome
的第 8 行和第 20 行,字段 session
被分配。
根据我的理解,SSB MyHome
不是由 J2EE 服务器(JBoss 4.2.2 GA)管理,因为它已被实例化为 GetAllResponses
的静态字段类而不是在 JNDI 上查找。因此,两个线程可以同时访问 MyHome
的同一个实例,并且由于会话存储在 session
字段中,因此第一个调用可以很容易地获得其< code>Session 替换为另一个 Session
,导致各种问题,包括 org.hibernate.SessionException: Session is close!
(第 9 行和第 21 行) >MyHome(例如,两个线程调用 findDataObject
,第一个线程在第二个线程运行第 8 行之后、第 9 行之前运行第 14 行)。
我说得对吗?
(First of all, this is not my code. Secondly, to protect the guilty, I have changed the class names to hide anything specific to my employer, so if things don't correspond with each other that's why!).
Can someone help me clear up a doubt please? I have been asked to investigate a problem with a full connection pool, and this code seems to smell.
We have lots of org.hibernate.SessionException: Session is closed!
in our logs, around the following code, which uses the connection pool that is behaving badly.
The calls come in via a web service:
1 @Stateless
2 @WebService(name="MyWebService", targetNamespace="http://www.mycompany.com/2010/01/WebService/myWebService")
3 @WebContext(contextRoot="/myContextRoot", secureWSDLAccess=false)
4 public class MyWebService implements IMyWebService {
6 @WebMethod
7 @NotNull
8 public ArrayList<SearchResult> performSearch(ArrayList<String> criteria) {
9 GetAllResponses caller = new GetAllResponses();
10 return caller.doSearch(criteria);
11 }
13 }
The GetAllResponses
class is as follows:
1 public class GetAllResponses {
2 private static MyHome myHome = new MyHome();
4 public SearchResult doSearch(ArrayList<String> criteria) {
5 return doSearchInternal(criteria.elementAt(0), criteria.elementAt(1));
6 }
8 private SearchResult doSearchInternal(String a, String b) {
9 DataObject info = myHome.findDataObject(a, b);
10 return info.getAsSearchResult();
11 }
12 }
And MyHome
is as follows:
1 @Stateless
2 @Local({MyHomeInterface.class})
3 public class MyHome {
4 private Session session;
6 public DataObject findDataObject(String a, String b) {
7 try {
8 this.session = MyHibernateUtil.getSessionFactory().getCurrentSession();
9 Transaction tx = this.session.beginTransaction();
10 //do stuff with session and return a DataObject
11 } catch (Exception ex) {
12 ex.printStackTrace();
13 } finally {
14 this.session.close();
15 }
16 }
18 public DataObject doAnotherFind(String a, String b) {
19 try {
20 this.session = MyHibernateUtil.getSessionFactory().getCurrentSession();
21 Transaction tx = this.session.beginTransaction();
22 //do stuff with session and return a DataObject
23 } catch (Exception ex) {
24 ex.printStackTrace();
25 } finally {
26 this.session.close();
27 }
28 }
30 }
Note how on line 2 of GetAllResponses
the MyHome
class is instantiated as a static field, and that on lines 8 and 20 of MyHome
the field session
is assigned.
From my understanding of things, the SSB MyHome
is not being managed by the J2EE server (JBoss 4.2.2 GA) as it has been instantiated as a static field of the GetAllResponses
class rather than being looked up on JNDI. Therefore, two threads could access the same instance of MyHome
at the same time, and because the session is stored in the field session
, the first call could very easily have its Session
replaced with another Session
, causing all sorts of problems including org.hibernate.SessionException: Session is closed!
on lines 9 and 21 of MyHome
(as an example, two threads call findDataObject
, the first thread runs line 14 just after the second thread has run line 8 and before it has run line 9).
Am I correct?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
是的,你是对的。
另外,请注意,即使 myHome 不是静态的,MyHome 返回的所有对象也将与会话断开连接。您将无法从 MyHome 外部初始化惰性属性。
会话变量也应该是 MyHome 方法中的局部变量,而不是实例变量。
但主要问题是无状态会话 bean 应该用于以声明方式划分事务。在 EJB 环境中,您不必打开、提交和回滚事务以及关闭会话。一切都应该由通过 sessionFactory.getCurrentSession() 实现的 JTA 事务同步来完成。
Yes, you're correct.
Also, be aware that even if myHome was not static, all the objects returned by the MyHome would be disconnected from the session. You won't be able to initialized lazy properties from outside of MyHome.
The session variable should also be a local variable in MyHome methods, rather than an instance variable.
But the main problem is that stateless session beans are supposed to be used to demarcate transactions declaratively. In an EJB environment, you shouldn't have to open, commit and rollback transactions, and to close sessions. Everything should be done by the JTA transaction synchronization implemented through sessionFactory.getCurrentSession().