JPA如何更新现有对象数据无异常?

时间:2012-10-24 17:22:53

标签: java jpa exception-handling auto-update

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

[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 ] ])

主对象类看起来像下面的代码。关于OneToMany存在一些变量。

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对象是man对象,就像上面的代码一样。在这个例子中,我检查对象是否没有他的主键LinkId然后用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();
                }
            }

        }

1 个答案:

答案 0 :(得分:0)

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

首先,您应该使用merge而不是persist。现在,考虑到这一点,merge方法也会抛出异常,因为JPA无法定义您要保留的实体是新实体还是普遍获取的实体,因为生命周期不一样。

如果您创建了一个对象并设置了它的id,那么该实体的状态为new,但如果您在该实体应该具有detached状态之前获取该实体。合并时,将正确更新分离的实体,但将保留新实体,并且由于获取了id,因此抛出异常。

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