调试 Hibernate“会话已关闭!” - 滥用SSB?

发布于 2024-10-21 08:32:40 字数 2855 浏览 3 评论 0原文

(首先,这不是我的代码。其次,为了保护有罪者,我更改了类名称以隐藏特定于我的雇主的任何内容,因此如果事情彼此不一致,这就是原因!)。

有人可以帮我解答疑问吗?我被要求调查完整连接池的问题,而这段代码似乎有味道。

我们的日志中有很多 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

少女的英雄梦 2024-10-28 08:32:40

是的,你是对的。

另外,请注意,即使 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().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文