2011-12-29 91 views
0

我有一個用戶登錄的JSF 2.0頁面,他有一個註銷選項(令人驚訝)。我的JBoss服務器配置允許最多7個線程(連接)。我用一個用戶測試多次登錄頁面,第七次嘗試後我得到Transaction not active這可能意味着註銷後連接不會回到池中並保持打開狀態。返回連接池

問:註銷並返回線程池中線程的方式是什麼?這個問題折磨了我很長一段時間。請幫忙。

下面是在我的JBoss standalone.xml爲數據源限制所述連接的配置:

<subsystem xmlns="urn:jboss:domain:datasources:1.0"> 
      <datasources> 
       <datasource jndi-name="java:jboss/MyJndiDS" pool-name="MyPoolDS" enabled="true" jta="true" use-java-context="false" use-ccm="true"> 
        <connection-url> 
         jdbc:postgresql://192.168.2.125:5432/t_report 
        </connection-url> 
        <driver> 
         org.postgresql 
        </driver> 
        <transaction-isolation> 
         TRANSACTION_READ_COMMITTED 
        </transaction-isolation> 
        <pool> 
         <min-pool-size> 
          3 
         </min-pool-size> 
         <max-pool-size> 
          7 
         </max-pool-size> 
         <prefill> 
          true 
         </prefill> 
         <use-strict-min> 
          false 
         </use-strict-min> 
         <flush-strategy> 
          FailingConnectionOnly 
         </flush-strategy> 
        </pool> 
        <security> 
         <user-name> 
          my_user 
         </user-name> 
         <password> 
          my_pass 
         </password> 
        </security> 
        <statement> 
         <prepared-statement-cache-size> 
          32 
         </prepared-statement-cache-size> 
        </statement> 
       </datasource> 
... 
... 
      </datasources> 
</subsystem> 

和註銷方法在@SessionScoped

import javax.faces.context.ExternalContext; 
... 
... 
@Inject ExternalContext ec; 

public void validateUserLogOut() { 

    HttpServletRequest request = (HttpServletRequest)ec.getRequest(); 
    request.getSession().invalidate(); 
    this.setUserLoggedIn(false); 
    navigation.logout(); 

} 

編輯:這裏是用戶在如何日誌。 希望這可以幫助。

public void validateLogUser() { 
    ResourceBundle bundle = ResourceBundle.getBundle("internationalization.language", context.getViewRoot().getLocale()); 
    String validation = logUser(); 
    if((validation == null) || validation.isEmpty()) { 
     context.addMessage(null, 
      new FacesMessage(FacesMessage.SEVERITY_WARN, 
      bundle.getString("wrongUsername"),bundle.getString("wrongUsername"))); 
    } else if (validation == "welcome") { 
     this.setUserLoggedIn(true); 
     navigation.login(); 
    } 
} 

其中logUser()是:

public synchronized String logUser() { 

    try { 
     EntityManagerUtil.getEntityManager().getTransaction().begin(); 
     System.out.println(user); 
     if(user.getUsername().isEmpty() || (user.getUsername() == null)) { 
      return null; 
     } 
     String password = user.getPassword(); 
     user = (UserBean) EntityManagerUtil.getEntityManager().find(UserBean.class, user.getUsername()); 
     if(user == null) { 
      HttpServletRequest request = (HttpServletRequest)ec.getRequest(); 
      request.getSession().invalidate(); 
     } 
     if(user.getPassword().equals(password)) { 
      log.info("User: " + user.getUsername() + " logged successfully."); 
      return "welcome"; 
     } else { 
      HttpServletRequest request = (HttpServletRequest)ec.getRequest(); 
      request.getSession().invalidate(); 
      return null; 
     } 
    } catch (Exception e) { 
     log.error("Error while logging in : \n\t" + e); 
     EntityManagerUtil.getEntityManager().getTransaction().rollback(); 
     return null; 
    } finally { 
     EntityManagerUtil.close(); 
    } 
} 

這是怎麼EntityManagerUtil.getEntityManager()作品:

/** 
* ThreadLocal instance that holds unique EntityManager per thread, 
* it means that every thread accessing this ThreadLocal will has it's own instance of EntityManager 
*/ 
private static final ThreadLocal<EntityManager> entitymanager = 
    new ThreadLocal<EntityManager>(); 

/** 
* @param persistenceUnit - String name of the persistece unit 
* to be used as declared inside persistence.xml 
* @return singleton instance of EntityManagerFactory 
*/ 
public synchronized static EntityManagerFactory initializeEntityManagerFactory(String persistenceUnit) { 
    if (entityManagerFactory == null) { 
     // Create the EntityManagerFactory 
     entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnit); 
    } 
    return entityManagerFactory; 
} 


/** 
* @return Singleton instance of EntityManager per Thread 
*/ 
public static EntityManager getEntityManager() { 
    initializeEntityManagerFactory("MyPersistenceUnit"); 
    EntityManager entityManager = entitymanager.get(); 

    // Create a new EntityManager 
    if (entityManager == null) { 
     entityManager = entityManagerFactory.createEntityManager(); 
     entitymanager.set(entityManager); 
    } 

    return entityManager; 
} 


/** 
* Close all ThreadLocals 
*/ 
public static void close() { 
    final EntityManager entityManager = entitymanager.get(); 
    entitymanager.set(null); 
    if (entityManager != null && entityManager.isOpen()) { 
     entityManager.close(); 
    } 
    if (entityManagerFactory != null && entityManagerFactory.isOpen()) { 
     entityManagerFactory.close(); 
    } 
} 
+2

請說明您如何管理登錄過程?看起來你正在手動管理連接,並且你忘了關閉連接。您是否在使用JPA + EJB或純JDBC來訪問數據庫? – 2011-12-29 15:02:35

+0

否則您的註銷代碼看起來很好。你不應該在乎線程或返回任何東西。 – 2011-12-29 15:09:02

+0

對不起,延誤了。我試圖展示可能對你最有幫助的事情。請讓我知道這是你的意思。 – nyxz 2011-12-29 15:23:13

回答

4

你重新發明輪子。請使用容器管理實體管理器注入@PersistenceContext註釋和EJB來管理事務。它會容易得多,而且容易出錯。

下面是一個簡單的DAO:

@Stateless 
public class UserDAO { 

    @PersistenceContext 
    private EntityManager entityManager; 

    public void insertUser(User user) { 
     entityManager.persist(user); 
    } 
} 

默認情況下,在每EJB方法是事務性的。您可以使用@TransactionAttribute註釋實現精細控制。這非常簡單。

+0

並感謝你的答案(弓) – nyxz 2011-12-29 15:46:26

+0

加上歡迎:) – 2011-12-29 15:52:08

+1

+1這個偉大的答案:) – 2011-12-29 16:04:11