2012-08-04 93 views
1

如果發生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; 
    } 
} 

回答

2

引述基思& Schincariol在「臨JPA 2」:

如果交易不存在, 那麼要麼修改操作會拋出異常 或改變根本不會被持久化到數據存儲。

確保您要堅持互動,與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實例上同一方法的調用。

現在,使用裝飾器將「工作者」與「事務服務」分開將使您能夠輕鬆步入Java EE,Spring或其他未來爲您管理事務的容器框架。例如,您DatabaseUtilsServices包含所有鍋爐板很可能成爲一個EJB裝飾的一部分:

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

好吧,我**認爲**做了這個訣竅,謝謝:)我打算玩一下,以確保一切。 – Thufir 2012-08-04 08:11:23

0

也許就足夠了Tu內,instanciates新文章前行右側插入如下幾行:

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

而且,如果從Article到New的關係,則可能必須手動持久化()新的Newsgroup sgroup沒有將其Cascade屬性設置爲PERSIST。

+0

哦,Newsgroup的默認構造函數的問題是它沒有意義,所以不能使用或持久化。關係被設置爲PERSIST。我如何手動持久化()新聞組,或者是否存在一些邏輯錯誤,以至於它永遠不會發生? – Thufir 2012-08-04 03:23:26

2

因爲JPA不具有「自動提交」模式(即無成交)。交易之外的操作應該延遲到下一個交易發生(而你的交易沒有)。

很顯然,某些JPA實現(如DataNucleus JPA)提供了完全的自動提交功能,因爲他們認爲這是一個非常有用的工具,可以簡化用戶的工作......所以也許你只是使用其中的一種那不允許。