JPA如何无例外更新现有对象数据



我尝试更新数据库中的现有数据行,但我得到了例外:

[EL Warning]: 2012-10-24 20:02:27.798--UnitOfWork(22664464)--Exception [EclipseLink-4002] (Eclipse Persistence Services -
2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '20-http://www.vilpra.lt/products/Foto/Aremikas/Katilas_zvake_big' for key 'PRIMARY' Error Code: 1062 Call: INSERT INTO x_links_media (image, link_id) VALUES (?, ?)  bind => [2 parameters bound] Query: InsertObjectQuery(database.entity.XLinksMedia[ xLinksMediaPK=database.entity.XLinksMediaPK[ linkId=20, image=http://www.link.lt/products.jpg ] ])

主对象类看起来像下面的代码。有一些带有关系的变量。

package database.entity;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlRootElement;
@Entity
@Table(name = "x_parser_links")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "XParserLinks.findAll", query = "SELECT x FROM XParserLinks x"),
    @NamedQuery(name = "XParserLinks.findByLinkId", query = "SELECT x FROM XParserLinks x WHERE x.linkId = :linkId"),
    @NamedQuery(name = "XParserLinks.findByPageId", query = "SELECT x FROM XParserLinks x WHERE x.pageId = :pageId"),
    @NamedQuery(name = "XParserLinks.findByLink", query = "SELECT x FROM XParserLinks x WHERE x.link = :link"),
    @NamedQuery(name = "XParserLinks.findByLevel", query = "SELECT x FROM XParserLinks x WHERE x.level = :level"),
    @NamedQuery(name = "XParserLinks.findByLinkType", query = "SELECT x FROM XParserLinks x WHERE x.linkType = :linkType"),
    @NamedQuery(name = "XParserLinks.findByCreateDate", query = "SELECT x FROM XParserLinks x WHERE x.createDate = :createDate"),
    @NamedQuery(name = "XParserLinks.findByDelDate", query = "SELECT x FROM XParserLinks x WHERE x.delDate = :delDate")})
public class XParserLinks implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "link_id")
    private Integer linkId;
    @Column(name = "page_id")
    private Integer pageId;
    @Column(name = "link")
    private String link;
    @Column(name = "level")
    private Integer level;
    @Column(name = "link_type")
    private Short linkType;
    @Column(name = "create_date")
    @Temporal(TemporalType.TIMESTAMP)
    private Date createDate;
    @Column(name = "del_date")
    @Temporal(TemporalType.TIMESTAMP)
    private Date delDate;
    @JoinColumn(name = "tev_link_id")
    @OneToOne(cascade = CascadeType.ALL)
    private XParserLinks tevas;
    @OneToMany(mappedBy = "xParserLink", targetEntity = XLinksMedia.class, cascade = CascadeType.ALL)
    private List<XLinksMedia> fotos;
    @OneToMany(mappedBy = "xParserLink", targetEntity = XLinksVarchar.class, cascade = CascadeType.ALL)
    private List<XLinksVarchar> atributes;    
    public XParserLinks() {
    }
    public XParserLinks(Integer linkId) {
        this.linkId = linkId;
    }
    public Integer getLinkId() {
        return linkId;
    }
    public void setLinkId(Integer linkId) {
        this.linkId = linkId;
    }
    public Integer getPageId() {
        return pageId;
    }
    public void setPageId(Integer pageId) {
        this.pageId = pageId;
    }
    public String getLink() {
        return link;
    }
    public void setLink(String link) {
        this.link = link;
    }
    public Integer getLevel() {
        return level;
    }
    public void setLevel(Integer level) {
        this.level = level;
    }
    public Short getLinkType() {
        return linkType;
    }
    public void setLinkType(Short linkType) {
        this.linkType = linkType;
    }
    public Date getCreateDate() {
        return createDate;
    }
    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }
    public Date getDelDate() {
        return delDate;
    }
    public void setDelDate(Date delDate) {
        this.delDate = delDate;
    }
    public XParserLinks getTevas() {
        return tevas;
    }
    public void setTevas(XParserLinks tevas) {
        this.tevas = tevas;
    }
    public List<XLinksMedia> getFotos() {
        return fotos;
    }
    public void setFotos(List<XLinksMedia> fotos) {
        this.fotos = fotos;
    }
    public List<XLinksVarchar> getAtributes() {
        return atributes;
    }
    public void setAtributes(List<XLinksVarchar> atributes) {
        this.atributes = atributes;
    }
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (linkId != null ? linkId.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 XParserLinks)) {
            return false;
        }
        XParserLinks other = (XParserLinks) object;
        if ((this.linkId == null && other.linkId != null) || (this.linkId != null && !this.linkId.equals(other.linkId))) {
            return false;
        }
        return true;
    }
    @Override
    public String toString() {
        return "database.entity.XParserLinks[ linkId=" + linkId + " ]";
    }
}

这是我要继续数据的代码。XParserLinks对象是上面的代码的人对象。在此示例中,我检查对象是否没有他的主要密钥链接,然后用persist创建新对象,而只是更新对象和他的值,但是我会像想更新现有对象之前一样得到例外。

        XParserLinks e = entry.getValue();
        if (e.getLinkId() == null) {
            try {
                TarpineManager.startTransaction();
                TarpineManager.persist(e);
                TarpineManager.commitTransaction();
            } catch (Exception ex) {
                ex.printStackTrace();
                if (TarpineManager.getInstance().getTransaction().isActive()) {
                    TarpineManager.rollbackTransaction();
                }
            }
        } else {
            try {
                TarpineManager.startTransaction();
                TarpineManager.commitTransaction();
            } catch (Exception ex) {
                ex.printStackTrace();
                if (TarpineManager.getInstance().getTransaction().isActive()) {
                    TarpineManager.rollbackTransaction();
                }
            }
        }

您是否有机会创建您的实体并逐力设置其ID?我看到您的班上有一个setLinkId(Integer linkId)方法。

首先,您应该使用merge而不是persist。现在,考虑到这一点,merge方法也将例外抛出,因为JPA无法定义您要坚持的实体是否是新的,或者是一个被置于的实体,或者是一个持久的信息,因为生命周期中的状态不是相同。

如果创建对象并设置其ID,则该实体具有状态new,但是如果您在实体之前将其获取detached状态。合并后,将正确更新一个独立的实体,但将持续使用一个新实体,并且由于采取ID,因此抛出了例外。

您拥有该实体的ID,因此您最好以前获取它们,然后更新对象,然后更新merge

最新更新