为什么hibernate给出了ConstraintException,就好像在已经存在的情况下尝试创建对象一样

时间:2013-09-10 21:51:08

标签: java hibernate

我在更新/创建CoverImage对象时使用saveOrUpdate()。偶尔我会在主键上遇到约束违规。

org.hibernate.exception.ConstraintViolationException: 
Unique index or primary key violation: "PRIMARY_KEY_6 
ON PUBLIC.COVERIMAGE(DATAKEY)"; SQL statement:

似乎它正在尝试创建一个新的CoverImage(INSERT)而不是更新现有的CoverImage(UPDATE),但我不知道为什么因为datakey被定义为类的@id而我设置了datakey。 / p>

我使用saveOrUpdate()而不是单独的save()和update()部分,因为代码是多线程的。我实际上在调用此方法之前检查实例是否存在,并且仅在对象不存在时调用,因此我不认为它已经存在,但总是存在这种情况的可能性。问题似乎大约发生在3000次左右。

这是Hibernate类

package com.jthink.songlayer;

import com.jthink.songlayer.utils.Base64Coder;
import org.hibernate.annotations.IndexColumn;
import org.hibernate.envers.Audited;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.stream.ImageInputStream;
import javax.persistence.*;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.CharBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *  An Image
 */
@Audited
@Entity
public class CoverImage
{

    public CoverImage()
    {

    }

    public CoverImage(byte[] imageData)
    {
        this.imageData=imageData;
    }

    @Id
    @Column(length = 1000)
    private String dataKey;

    @Version
    private int version;

    public String getDataKey()
    {
        return dataKey;
    }

    public void setDataKey(String dataKey)
    {
        this.dataKey = dataKey;
    }

    @Lob
    private byte[]  imageData;

    @Lob
    private byte[]  thumbnailData;

    private String  mimeType;
    private int     width;
    private int     height;
    private boolean isLinked;

    @org.hibernate.annotations.Index(name = "IDX_SOURCE")
    private String  source;

    @Lob
    private byte[]  resizedImageData;
    private int     resizedWidth;
    private int     resizedHeight;

    public byte[] getImageData()
    {
        return imageData;
    }

    public void setImageData(byte[] imageData)
    {
        this.imageData = imageData;
    }

    public byte[] getThumbnailData()
    {
        return thumbnailData;
    }

    public void setThumbnailData(byte[] thumbnailData)
    {
        this.thumbnailData = thumbnailData;
    }

    public String getMimeType()
    {
        return mimeType;
    }

    public void setMimeType(String mimeType)
    {
        this.mimeType = mimeType;
    }

    public int getWidth()
    {
        return width;
    }

    public void setWidth(int width)
    {
        this.width = width;
    }

    public int getHeight()
    {
        return height;
    }

    public void setHeight(int height)
    {
        this.height = height;
    }

    public boolean isLinked()
    {
        return isLinked;
    }

    public void setLinked(boolean linked)
    {
        isLinked = linked;
    }


    public String getSource()
    {
        return source;
    }

    public void setSource(String source)
    {
        this.source = source;
    }

    public byte[] getResizedImageData()
    {
        return resizedImageData;
    }

    public void setResizedImageData(byte[] resizedImageData)
    {
        this.resizedImageData = resizedImageData;
    }

    public int getResizedWidth()
    {
        return resizedWidth;
    }

    public void setResizedWidth(int resizedWidth)
    {
        this.resizedWidth = resizedWidth;
    }

    public int getResizedHeight()
    {
        return resizedHeight;
    }

    public void setResizedHeight(int resizedHeight)
    {
        this.resizedHeight = resizedHeight;
    }

    /**
     * Create message digest of the byte data
     * <p/>
     * This uniquely identifies the imagedata, but takes up much less room than the original data
     *
     * @param imageData
     * @return
     */
    public static byte[] getImageDataDigest(byte[] imageData)
    {
        //Calculate checksum
        MessageDigest md;
        try
        {
            md = MessageDigest.getInstance("MD5");
        }
        catch (NoSuchAlgorithmException nsae)
        {
            //This should never happen
            throw new RuntimeException(nsae);
        }

        md.reset();
        md.update(imageData);
        return md.digest();
    }

    public static String createKeyFromData(byte[] imageData)
    {
        try
        {
            String base64key = CharBuffer.wrap(Base64Coder.encode(getImageDataDigest(imageData))).toString();
            return base64key;
        }
        catch (NullPointerException npe)
        {
            throw new RuntimeException("Unable to create filename from sum");
        }
    }
}

这是使用它的代码

   try
    {
        //Create thumbnail
        BufferedImage           thumb = ArtworkHelper.resizeToThumbnail(newBuffered, THUMBNAIL_SIZE);
        ByteArrayOutputStream   baos    = new ByteArrayOutputStream();
        ImageIO.write(thumb, ImageFormats.V22_JPG_FORMAT.toLowerCase(), baos);
        session = com.jthink.songlayer.hibernate.HibernateUtil.getSession();
        Transaction tx  = session.beginTransaction();
        coverImage = new CoverImage(imageData);
        coverImage.setThumbnailData(baos.toByteArray());
        coverImage.setDataKey(CoverImage.createKeyFromData(imageData));
        coverImage.setSource(source);
        coverImage.setWidth(newBuffered.getWidth());
        coverImage.setHeight(newBuffered.getHeight());
        coverImage.setMimeType(ImageFormats.getMimeTypeForBinarySignature(imageData));
        session.saveOrUpdate(coverImage);
        tx.commit();
        return coverImage;
    }
    catch(IOException ioe)
    {
        MainWindow.logger.log(Level.SEVERE, "Failed Creating Thumbnails" + ioe.getMessage(), ioe);
        return null;
    }
    catch(StaleObjectStateException sose)
    {
        return SongCache.findCoverImageBySourceInOwnSession(source);
    }
    finally
    {
        HibernateUtil.closeSession(session);
    }

完整堆栈跟踪

10/01/2013 09.17.12:com.jthink.songkong.analyse.analyser.DiscogsSongGroupMatcher:call:SEVERE: Failed AddSongToDatabase:Unique index or primary key violation: "PRIMARY_KEY_6 ON PUBLIC.COVERIMAGE(DATAKEY)"; SQL statement:
insert into CoverImage (height, imageData, isLinked, mimeType, resizedHeight, resizedImageData, resizedWidth, source, version, width, dataKey) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [23505-166]
org.hibernate.exception.ConstraintViolationException: Unique index or primary key violation: "PRIMARY_KEY_6 ON PUBLIC.COVERIMAGE(DATAKEY)"; SQL statement:
insert into CoverImage (height, imageData, isLinked, mimeType, resizedHeight, resizedImageData, resizedWidth, source, version, width, dataKey) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [23505-166]
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:128)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:129)
at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81)
at $Proxy27.executeUpdate(Unknown Source)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:56)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2962)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3403)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:88)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:275)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1210)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:399)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at com.jthink.songkong.db.SongCache.saveNewCoverImage(SongCache.java:332)

2 个答案:

答案 0 :(得分:0)

看起来您正在以下行创建密钥:

CoverImage.createKeyFromData(imageData)

你可能在两个imageData对象中使用的函数中发生了碰撞,这有时会导致这个问题,如果它只是主键那么你可以使用很多其他方法来生成一个简单的设置可能很简单UUID。

干杯!!

答案 1 :(得分:0)

主键在数据库中必须是唯一的,并且您通过调用以下方法来分配CoverImage的主键。但如果有两个相同的imageData传入怎么办?我猜测会创建一个重复的主键,这将导致ConstraintException。

   public static String createKeyFromData(byte[] imageData)
{
    try
    {
        String base64key = CharBuffer.wrap(Base64Coder.encode(getImageDataDigest(imageData))).toString();
        return base64key;
    }
    catch (NullPointerException npe)
    {
        throw new RuntimeException("Unable to create filename from sum");
    }
}