0

我正在使用 JPA 框架来实现信息的数据库持久性。

这就是我使用我创建的类的方式:

public class ManageConnection {

 private static EntityManagerFactory emf = null;
 private static EntityManager em = null;
 private static String persitenceName="locationtracker";

 public static EntityManager getEntityManager(){
    if(emf==null || !emf.isOpen())
        emf =  Persistence.createEntityManagerFactory(persitenceName);
    if(em==null || !em.isOpen())
        em=emf.createEntityManager();

    return em;
 }
 public static void closeEntityManager(){
    if(em!=null && em.isOpen())
        em.close()
 }
}

然后在我的servlet中我是这样使用的:

public void doPost(blablah){   
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    for(blah blah){

         Manageconnection.getEntityManager().getTransaction().begin();
            <PersistenceObject> objName = new <PersistenceObject>();
                 //properties of the objName to persist
         ManageConnection.getEntityManager().persist(<objName>);
         Manageconnection.getEntityManager().getTransaction().commit();
    }

    Manageconnection.closeEntityManager();
}

现在我的问题是,每当我将值传递给我的 Servlet 时,我都会得到Transaction is active异常,同样的代码在没有 Servlet 的情况下也能完美运行,我的意思是在 Test 类中使用 main 方法,它运行起来像魅力一样,但它抛出在 Servlet 中运行时出现异常。

请帮助我........ ;(提前感谢,Ankur

4

3 回答 3

1

所有你的EntityManagerFactoryEntityManagerFactory被使用的static。它是类级别,适用于ManageConnection. 起初,如果ManageConnection创建了一个实例,它将共享另一个实例ManageConnection。我的建议是尝试不使用static.

于 2012-10-15T15:50:02.440 回答
1
  1. 我假设您不想使用 EJB,而是想使用 POJO。
    (注意有一个简单的解决方案,会话 Bean 执行 JPA 操作,Servlet 调用 EJB - 更少的代码,更少的丑陋,做你想要的。)

  2. 每个 servlet 会话都应该有自己的实体管理器实例。从类 ManageConnection 中删除所有“静态”情况。然后在您的 servlet 中,当您创建 HttpSession 时,另外创建一个 ManageConnection 实例并将其作为属性存储在会话中。

    公共类 MyServlet 扩展 HttpServlet {

    private ManageConnections getManageConnections(HttpSession sess) {
        ManageConnection manageConnection = 
            (ManageConnection)sess.getAttribute("userManageConnection");
        if (manageConnection == null) {
            ManageConnection manageConnection = new ManageConnection();
            sess.setAttribute("userManageConnection", manageConnection);
        }
    }
    
    public void doPost(HttpServletRequest req, HttpServletResponse resp) 
         throws ServletException, IOException {
       this.processRequest(req, resp);
    }
    
    public void processRequest(HttpServletRequest req, HttpServletResponse resp) 
         throws ServletException, IOException {
        HttpSession sess = req.getSession(true);
        ManageConnections manageConnections = this.getManageConnections(sess);
        // remaining JPA operations
    }
    

    }

  3. 获取实体管理器:

    // inside processRequest() above
    EntityManager em = manageConnection.getEntityManager();
    
  4. 开始 Tx,做实体操作,结束 Tx

    // inside processRequest() above
     em.getTransaction().begin();
     <PersistenceObject> objName = new <PersistenceObject>();
     //properties of the objName to persist
     em.persist(<objName>);
     em.getTransaction().commit();
    
  5. 在用户完成会话之前关闭 EntityManager。这很重要,因为如果没有它,某些实现将需要经常重新启动 - 特别是在开发期间,当您经常重建和重新部署时(我正在看着您,Glassfish 上的 EclipseLink,使用 netbeans 模块部署)。

     make servlet:  extends HttpSessionListener
    
     // add the following methods, so we get a callback to sessionDestroyed when the 
     // session is closed via user logout (terminateSession) or session timeout:
    
     public void init(ServletConfig config) throws ServletException {
        config.getServletContext().addListenter(this.class.getName());
     }
    
    
     public void sessionCreated(HttpSessionEvent se) {
     }
    
     public void sessionDestroyed(HttpSessionEvent se) {
           ManageConnections manageConnections = this.getManageConnections();
           manageConnections.getEntityManager().close();
           manageConnections.getEntityManagerFactor().close();
     }
    

正如我所说 - 有点难看,因为我们在无状态 Servlet 中使用了一个非常有状态的应用程序托管实体管理器。在无状态会话 Bean 中使用事务范围实体管理器或在有状态会话 Bean 中使用扩展范围(或应用程序管理)实体管理器要干净得多...... 相当多的 JPA,但比听起来容易。:-)

于 2012-10-16T08:29:02.890 回答
0

我创建了两个这样的类:

 //This class has the EntityManagerFactory instance that is going to be shared between the classes
 public class ManageConnection {

  protected static EntityManagerFactory emf = null;
  private static String persitenceName="locationtracker";

  //Anonymous Block that is going to be called (beofre) on every call for constructor of this class
  //whether through inheritance or normal instantiation
  {
    if(emf==null || !emf.isOpen())
        emf =  Persistence.createEntityManagerFactory(persitenceName);
  }


  public static EntityManagerFactory getEntityManagerFactory(){
    return ManageConnection.emf;
  }
}
//This class actually handles the trasactional management
 public class ManageTransaction extends ManageConnection{

   /**
    * 
    */
   public ManageTransaction() {
    super();
    this.entityManager = emf.createEntityManager();
    this.transaction = this.entityManager.getTransaction();

   }

   /**
    * @param entityManager
    * @param transaction
    */
   public ManageTransaction(EntityManager entityManager,EntityTransaction transaction) {
    super();
    this.entityManager = entityManager;
    this.transaction = transaction;
   }

   private EntityManager entityManager;
   private EntityTransaction transaction;

   /**
    * @return the entityManager
    */
   public EntityManager getEntityManager() {
    return entityManager;
   }

   /**
    * @param entityManager the entityManager to set
    */
   public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
   }

   /**
    * @return the transaction
    */
   public EntityTransaction getTransaction() {
    return transaction;
   }

   /**
    * @param transaction the transaction to set
    */
   public void setTransaction(EntityTransaction transaction) {
    this.transaction = transaction;
   }

   public void closeEntityManager(){
    if(entityManager!=null && entityManager.isOpen()){
        entityManager.close();
    }
   }

   public void close(){
    this.closeEntityManager();
   }

   public void flush(){
    entityManager.flush();
   }

   public void begin(){
    this.transaction.begin();
   }

   public void commit(){
    this.flush();
    this.transaction.commit();
   }

   public void persist(Object objToPersist){
    this.entityManager.persist(objToPersist);
   }
 }//end of ManageTransaction class

现在,如果我想使用它,我会这样使用:

.
.
.
.
.
.
ManageTransaction mt = new ManageTransaction();

方案 1

 mt.getEntityManager().find(blah,blah);//works perfectly

方案 2

mt.begin();
<PersistenceObject> objName = new <PersistenceObject>();
mt.persist(objName);
mt.close();

方案 3

String jpaquery = "blah blah";
TypedQuery<ClassType> tq = mt.getEntityManager().createQuery(jpaquery,<Class>.class);
List<ClassType> all = tq.getResultList();

这样,每次不需要创建新事务时,我只需创建一个事务并在我的班级的每个地方都使用该事务,最后关闭它。

这样我共享EntityManager的问题就解决了,因此在任何情况下都不会抛出异常。

:)

于 2012-10-16T12:59:58.700 回答