【问题标题】:EntityManager.persist not workingEntityManager.persist 不工作
【发布时间】:2014-05-02 14:26:30
【问题描述】:

我有一个测试 servlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        EntityManager em = EMF.get().createEntityManager();
        em.getTransaction().begin()
        DBManager.getInstance().eraseDB();
        em.getTransaction().commit();
        em.getTransaction().begin();
        if(DBManager.getInstance().createUser("first", "second"))
            writer.print("done.");
        else
            writer.print("failed.");
        em.getTransaction().commit();

    }

方法eraseDB是:

@SuppressWarnings("unchecked")
    public void eraseDB(){
        EntityManager em = EMF.get().createEntityManager();
        Query q = em.createQuery("select u from User u");
        List<User> list = q.getResultList(); 
        for(User u : list){
            em.remove(u);   
        }       
    }

createUser的方法是:

public static synchronized boolean createUser(String username, String password) {
        EntityManager em = EMF.get().createEntityManager();
        Query q = em.createQuery("select u from User u");
        @SuppressWarnings("unchecked")
        List<User> list = q.getResultList();
        if(list.size() > 0)
            return false;
        User u = new User();
        u.setPassword(password);
        u.setUsername(username);
        em.persist(u);
        return true;
    }

在 servlet 调用之后,我从 createUser 方法得到了 true,但数据存储是空的。

为什么persist 不起作用?我做错了什么?
欢迎提供有关此架构的任何其他建议,谢谢。

【问题讨论】:

  • 您使用第一个实体管理器启动并提交事务,但您使用第二个不同的实体管理器进行持久化。
  • @JBNizet 谢谢。但是,如果我在持久化之前/之后放置一个事务开始/提交,在擦除数据库中的 for 循环之前/之后放置另一个,则存在并发问题(按住 F5 会出现异常或将两个元素放入数据库)

标签: jakarta-ee jpa persistence


【解决方案1】:

根据 Jb nizet 的回答:
当您明确指定一个事务(使用em.getTransaction.begin/commit/rollback)时,如果第一个事务未提交或回滚,则您无法开始第二个事务。在您的代码中,您应该将事务保存到每个 DbManager 的方法中,如下所示:

 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws    ServletException, IOException {
        EntityManager em = Emf.get().createEntityManager();
        DBManager.getInstance().eraseDB(em);
        if(DBManager.getInstance().createUser(em,"first", "second"))
            writer.print("done.");
        else
            writer.print("failed.");

    }

public void eraseDB(EntityManager em){
    Query q = em.createQuery("SELECT u FROM User u");
    List<User> list = q.getResultList();
    Try{
        em.getTransaction().begin(); 
        for(User u : list){
           em.remove(u);   
        }
        em.getTransaction().commit();
    }catch(Exception ex){
        em.getTransaction().rollback();
    }   
}

public static synchronized boolean createUser(EntityManager em, String username, String password) {
        Query q = em.createQuery("SELECT u FROM User u");
        List<User> list = q.getResultList();
        if(list.size() > 0)
            return false;
        User u = new User();
        u.setPassword(password);
        u.setUsername(username);
        Try{
            em.getTransaction().begin();
            em.persist(u);
            em.getTransaction().commit();
            return true;
        }catch(Exception ex){
            em.getTransaction().rollback();
            return false;
       }
    }

【讨论】:

  • 谢谢,但我更喜欢将 em 作为 DBManager 的属性,因为我不喜欢将它作为参数传递给每个方法。
  • 是的,可以,但我没有看到您的商务舱。将您的 EM 作为静态 final 和 VOLATILE 放入您的业务类,以使您的 EM 线程安全
  • 谢谢,只有两个问题:如果 DBManager 是单例,是否需要 static 关键字?如果所有 DBManager 方法都同步,是否需要 volatile 关键字? (可选的第三个问题:在这种情况下 volatile 比 synchronized 更好?)。再次感谢您。
  • 对不起,我说错了,static 关键字不是必需的,只需将您的 EM 声明为私有 final ( final 因为您的 EM 不会改变)。对于您的 DbManager getinstance 方法,您可以使用不同的方法来实例化您的 DbManager 类,请在此页面java.dzone.com/articles/singleton-design-pattern 报告您。希望对您有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-31
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多