在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 happent" + 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 "nmessageNumbert" + messageNumber;
}
public int getMessageNumber() {
return messageNumber;
}
public void setMessageNumber(int messageNumber) {
this.messageNumber = messageNumber;
}
}
引用Keith&Schincariol在"Pro 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;
}
}
您很快就会发现这是常见的锅炉铭牌代码。考虑使用装饰器:
- 创建一个接口,定义
DatabaseUtils
提供的服务/方法 - 让
DatabaseUtils
实现该接口 - 创建一个实现接口的
DataUtilsServices
(decorator)。它的实现将包含管理事务的代码,其中工作代码("您的代码转到这里")将成为对DatabaseUtils
实例上相同方法的调用
现在,使用decorator将"worker"与"transactional service"分离,这将使您能够在未来轻松地进入Java EE、Spring或其他为您管理事务的容器框架。例如,包含所有锅炉板的DatabaseUtilsServices
很可能成为EJB装饰器的一部分:
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void persistArticle(Message message, Folder folder) {
return databaseUtils.persistArticle(message, folder);
}
因为JPA没有"自动提交"模式(即没有事务)。事务之外的操作应该延迟到下一个事务发生(而您的操作没有)。
显然,一些JPA实现(如DataNucleus JPA)提供了完全的自动提交功能,因为他们认为这是一种非常有用的工具,可以简化用户的工作。。。所以也许你只是在使用一个不允许这样做的。
也许在表示新文章的行之前插入以下行就足够了:
if (newsgroup==null) {
newsgroup = new NewsGroup();
}
此外,如果从Article到Newsgroup的关系没有将其Cascade属性设置为persist,则可能需要手动持久化()新的Newsgroup。