3

我在更新/创建 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。

我使用 saveOrUpdate() 而不是单独的 save() 和 update() 部分,因为代码是多线程的。我实际上在调用此方法之前检查实例是否存在,并且仅在对象不存在时才调用,所以我不希望它已经存在,但总是有这种可能性。该问题似乎大约在 3000 次中出现 1 次。

这是休眠类

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)
4

2 回答 2

0

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

CoverImage.createKeyFromData(imageData)

可能在您用于两个 imageData 对象的函数中发生冲突,这有时会导致此问题,如果它只是主键,那么您可以使用许多其他方法来生成主键,就像设置 UUID 一样简单。

干杯!!

于 2013-09-11T04:24:58.740 回答
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");
    }
}
于 2013-09-11T08:03:09.203 回答