【问题标题】:why isn't a new entity persisted?为什么不保留一个新实体?
【发布时间】:2012-08-02 01:21:39
【问题描述】:

如果出现NoResultException,我如何实例化和持久化Newsgroup 实体?

package net.bounceme.dur.usenet.driver;

import java.util.logging.Logger;
import javax.mail.Folder;
import javax.mail.Message;
import javax.persistence.*;
import net.bounceme.dur.usenet.model.Article;
import net.bounceme.dur.usenet.model.Newsgroup;

class DatabaseUtils {

    private static final Logger LOG = Logger.getLogger(DatabaseUtils.class.getName());
    private EntityManagerFactory emf = Persistence.createEntityManagerFactory("USENETPU");
    private EntityManager em = emf.createEntityManager();

    public void persistArticle(Message message, Folder folder) {
        //do all the persistence here?
        String fullNewsgroupName = folder.getFullName();
        Newsgroup newsgroup = null;
        TypedQuery<Newsgroup> query = em.createQuery("SELECT n FROM Newsgroup n WHERE n.newsgroup = :newsGroupParam", Newsgroup.class);
        query.setParameter("newsGroupParam", fullNewsgroupName);
        try {
            newsgroup = query.getSingleResult();
            LOG.info("found " + query.getSingleResult()); //ok
        } catch (javax.persistence.NoResultException e) {
            LOG.info(e + "\ncould not find " + fullNewsgroupName); //ok
            newsgroup = new Newsgroup(folder);
            //it seems like the persist statement never executes...
            em.persist(newsgroup);
        } catch (NonUniqueResultException e) {
            LOG.info("\nshould never happen\t" + fullNewsgroupName); //not ok, should never execute
        }
        //need some mechanism to ensure that newsgroup is never a null reference
        Article article = new Article(message, newsgroup);
        em.persist(article); //never seems to execute..
    }

    public void close() {
        em.close();
        emf.close();//necessary?
    }
}

现在,似乎一遍又一遍地找不到该查询的结果:

run:
DEBUG: nntp: newsrc loading /home/thufir/.newsrc
DEBUG: nntp: newsrc load: 5 groups in 30ms
Aug 03, 2012 6:04:47 PM net.bounceme.dur.usenet.driver.FetchBean <init>
INFO: [gwene.com.androidcentral, gwene.com.blogspot.emacsworld, gwene.com.blogspot.googlecode, gwene.com.blogspot.googlereader, gwene.com.economist]
[EL Info]: 2012-08-03 18:04:51.277--ServerSession(28034142)--EclipseLink, version: Eclipse Persistence Services - 2.3.0.v20110604-r9504
[EL Info]: 2012-08-03 18:04:52.417--ServerSession(28034142)--file:/home/thufir/NetBeansProjects/USENET/build/classes/_USENETPU login successful
[EL Warning]: 2012-08-03 18:04:52.557--ServerSession(28034142)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'usenet.ARTICLE' doesn't exist
Error Code: 1146
Call: ALTER TABLE ARTICLE DROP FOREIGN KEY FK_ARTICLE_NEWSGROUP_ID
Query: DataModifyQuery(sql="ALTER TABLE ARTICLE DROP FOREIGN KEY FK_ARTICLE_NEWSGROUP_ID")
[EL Warning]: 2012-08-03 18:04:52.572--ServerSession(28034142)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'ARTICLE'
Error Code: 1051
Call: DROP TABLE ARTICLE
Query: DataModifyQuery(sql="DROP TABLE ARTICLE")
[EL Warning]: 2012-08-03 18:04:52.65--ServerSession(28034142)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'NEWSGROUP'
Error Code: 1051
Call: DROP TABLE NEWSGROUP
Query: DataModifyQuery(sql="DROP TABLE NEWSGROUP")
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.androidcentral
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.androidcentral
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.androidcentral
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.androidcentral
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.androidcentral
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.androidcentral
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.androidcentral
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.androidcentral
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.blogspot.emacsworld
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.blogspot.googlecode
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.blogspot.googlecode
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.blogspot.googlecode
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.blogspot.googlecode
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.blogspot.googlecode
Aug 03, 2012 6:04:54 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.blogspot.googlecode
Aug 03, 2012 6:04:55 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
[EL Info]: 2012-08-03 18:04:55.344--ServerSession(28034142)--file:/home/thufir/NetBeansProjects/USENET/build/classes/_USENETPU logout successful
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.blogspot.googlecode
Aug 03, 2012 6:04:55 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.blogspot.googlecode
Aug 03, 2012 6:04:55 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.economist
Aug 03, 2012 6:04:55 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.economist
Aug 03, 2012 6:04:55 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.economist
Aug 03, 2012 6:04:55 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.economist
Aug 03, 2012 6:04:55 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.economist
Aug 03, 2012 6:04:55 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.economist
Aug 03, 2012 6:04:55 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.economist
Aug 03, 2012 6:04:55 PM net.bounceme.dur.usenet.driver.DatabaseUtils persistArticle
INFO: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
could not find gwene.com.economist
Aug 03, 2012 6:04:55 PM net.bounceme.dur.usenet.driver.FetchBean <init>
INFO: **************************done
BUILD SUCCESSFUL (total time: 11 seconds)

当不存在唯一的Newsgroup 时,如何确保将新实体持久保存到数据库中?如果不是结果,那至少是代码的意图。

新闻组:

package net.bounceme.dur.usenet.model;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
import javax.mail.Folder;
import javax.persistence.*;

@Entity
public class Newsgroup implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger.getLogger(Newsgroup.class.getName());
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column //@Unique @UniqueConstraint interface..?
    private String newsgroup;
    @OneToMany(mappedBy = "newsgroup", cascade = CascadeType.PERSIST)
    private Set<Article> articles = new HashSet<>();

    public Newsgroup() {
        //should not create a newsgroup without a Folder
    }

    public Newsgroup(Folder folder) {
        newsgroup = folder.getFullName();//if row already exists, then what?
        LOG.fine(newsgroup);    
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Newsgroup)) {
            return false;
        }
        Newsgroup other = (Newsgroup) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return newsgroup;
    }
}

和文章:

package net.bounceme.dur.usenet.model;

import java.io.Serializable;
import java.util.logging.Logger;
import javax.mail.Message;
import javax.persistence.*;

@Entity
public class Article implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger.getLogger(Article.class.getName());
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column
    private int messageNumber;
    @ManyToOne(cascade = CascadeType.PERSIST)
    private Newsgroup newsgroup;

    public Article() {
    }

    public Article(Message message, Newsgroup newsgroup) {
        messageNumber = message.getMessageNumber();
        this.newsgroup = newsgroup;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Article)) {
            return false;
        }
        Article other = (Article) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "\nmessageNumber\t" + messageNumber;
    }

    public int getMessageNumber() {
        return messageNumber;
    }

    public void setMessageNumber(int messageNumber) {
        this.messageNumber = messageNumber;
    }
}

【问题讨论】:

    标签: java jpa persistence jpql toplink


    【解决方案1】:

    在“Pro JPA 2”中引用 Keith 和 Schincariol:

    如果交易不存在, 那么修改操作都会抛出异常 否则更改将永远不会持久保存到数据存储中。

    确保您希望与EntityManager em 保持的交互在事务的上下文中:

    public void persistArticle(Message message, Folder folder) {
        em.getTransaction().begin();
        try {
            // your code goes here; possibly current body of persistArticle(..)
    
            em.getTransaction().commit();
        } catch (final RuntimeException e) {
            if (em.getTransaction().isActive()) {
                em.getTransaction().rollback();
            }
    
            throw e;
        }
    }
    

    您很快就会发现这是常见的样板代码。考虑使用decorator

    • 创建一个接口,定义DatabaseUtils 提供的服务/方法。
    • DatabaseUtils 实现该接口。
    • 创建一个实现接口的DataUtilsServices(装饰器)。它的实现将包含管理事务的代码,其中工作代码(“您的代码在此处”)成为对 DatabaseUtils 实例上相同方法的调用。

    现在使用装饰器将“worker”与“transactional service”分开将使您能够在未来轻松地进入 Java EE、Spring 或其他为您管理事务的容器框架。例如,包含所有样板的 DatabaseUtilsServices 很可能成为 EJB 装饰器的一部分:

    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void persistArticle(Message message, Folder folder) {
        return databaseUtils.persistArticle(message, folder);
    }
    

    【讨论】:

    • 好的,我认为成功了,谢谢 :) 我将尝试一下以确保。
    【解决方案2】:

    因为 JPA 没有“自动提交”模式(即没有事务)。事务之外的操作应该延迟到下一个事务发生(而你的不会)。

    显然,一些 JPA 实现(例如 DataNucleus JPA)提供了完整的自动提交功能,因为他们认为这是一种非常有用的工具,可以简化用户的工作……所以也许您只是在使用其中一个那些不允许的。

    【讨论】:

      【解决方案3】:

      也许在实例化新文章的行之前插入以下行就足够了:

      if (newsgroup==null) {
          newsgroup = new NewsGroup();
      }
      

      此外,如果从文章到新闻组的关系没有将其 Cascade 属性设置为 PERSIST,您可能必须手动持久化()该新新闻组。

      【讨论】:

      • 哦,Newsgroup 的默认构造函数的问题是它没有意义,所以不能使用或持久化。该关系设置为 PERSIST。如何手动持久化()新闻组,或者是否存在一些逻辑错误使其永远不会发生?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多