1

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

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

我们的日志中有很多关于org.hibernate.SessionException: Session is closed!以下代码的内容,这些代码使用了表现不佳的连接池。

呼叫通过 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 }

请注意如何GetAllResponsesMyHome类的第 2 行实例化为静态字段,并在第 8 行和第 20 行分配MyHome该字段。session

根据我对事物的理解,SSBMyHome不是由 J2EE 服务器(JBoss 4.2.2 GA)管理的,因为它已被实例化为GetAllResponses类的静态字段,而不是在 JNDI 上查找。因此,两个线程可以同时访问同一个实例MyHome,并且由于会话存储在字段中session,第一次调用很容易Session被另一个调用替换Session,从而导致各种问题,包括org.hibernate.SessionException: Session is closed!第 9 行和第 21 行MyHome(例如,两个线程调用findDataObject,第一个线程在第二个线程运行第 8 行之后和第 9 行之前运行第 14 行)。

我对么?

4

1 回答 1

2

是的,你是对的。

另外,请注意,即使 myHome 不是静态的,MyHome 返回的所有对象也会与会话断开连接。您将无法从 MyHome 之外初始化惰性属性。

session 变量也应该是 MyHome 方法中的局部变量,而不是实例变量。

但主要问题是无状态会话 bean 应该用于以声明方式划分事务。在 EJB 环境中,您不必打开、提交和回滚事务以及关闭会话。一切都应该由通过 sessionFactory.getCurrentSession() 实现的 JTA 事务同步来完成。

于 2011-03-10T12:11:37.653 回答