为什么hibernate会给出ConstraintException,就好像试图在已经存在的时候创建对象一样 [英] Why is hibernate giving ConstraintException as if trying to create object when one already exists

查看:93
本文介绍了为什么hibernate会给出ConstraintException,就好像试图在已经存在的时候创建对象一样的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  org.hibernate.exception.ConstraintViolationException:
唯一索引或主键违例:PRIMARY_KEY_6
ON PUBLIC.COVERIMAGE(DATAKEY); SQL语句:

它似乎试图创建一个新的CoverImage(INSERT),而不是更新现有的CoverImage(更新),但我不知道为什么,因为datakey被定义为类的@id和Im设置数据键。

我使用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;
$ b $ / **
*图片
* /
@评估
@实体
公共类CoverImage
{
$ b $ public CoverImage()
{

}

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

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

@版本
private int version;

public String getDataKey()
{
return dataKey;
}

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

@Lob
private byte [] imageData;

@Lob
私人字节[] thumbnailData;

私人字符串mimeType;
private int width;
private int height;
private boolean isLinked;

@ org.hibernate.annotations.Index(name =IDX_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;
}

/ **
*创建字节数据的消息摘要
*< p />
*这个唯一标识图像数据,但占用的空间比原始数据少得多
*
* @param imageData
* @return
* /
public static byte [] getImageDataDigest(byte [] imageData)
{
//计算校验和
MessageDigest md;
尝试
{
md = MessageDigest.getInstance(MD5);
}
catch(NoSuchAlgorithmException nsae)
{
//这不应该发生
抛出新的RuntimeException(nsae);
}

md.reset();
md.update(imageData);
返回md.digest();

$ b $ public static String createKeyFromData(byte [] imageData)
{
try
{
String base64key = CharBuffer.wrap(Base64Coder .encode(getImageDataDigest(的imageData)))的toString();
返回base64key;

catch(NullPointerException npe)
{
throw new RuntimeException(Unable to create filename from sum);
}
}
}

这是代码使用它

 尝试
{
//创建缩略图
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();
返回coverImage;
}
catch(IOException ioe)
{
MainWindow.logger.log(Level.SEVERE,Failed Creating Thumbnails+ ioe.getMessage(),ioe);
返回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:唯一索引或主键违规:PRIMARY_KEY_6 ON PUBLIC .COVERIMAGE(DATAKEY); SQL语句:
插入到CoverImage(height,imageData,isLinked,mimeType,resizedHeight,resizedImageData,resizedWidth,source,version,width,dataKey)值(?,?,?,?,?,?,?,? ,?,?,?)[23505-166]
org.hibernate.exception.ConstraintViolationException:唯一索引或主键违例:PRIMARY_KEY_6 ON PUBLIC.COVERIMAGE(DATAKEY); SQL语句:
插入到CoverImage(height,imageData,isLinked,mimeType,resizedHeight,resizedImageData,resizedWidth,source,version,width,dataKey)值(?,?,?,?,?,?,?,? ,?,?,?)[23505-166]
位于org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:128)
位于org.hibernate.exception.internal.StandardSQLExceptionConverter。将org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
转换为(StandardSQLExceptionConverter.java:49)
。在org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:129)上转换(SqlExceptionHelper.java:110)
org.hibernate.engine.jdbc.internal处的
。 proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81)
at $ Proxy27.executeUpdate(Unknown Source)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBa tch(NonBatchingBatch.java:56)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2962)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister。 java:3403)
在org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:88)
在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)
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)
在org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:399)
在org.hibernate.engine.transaction.intern $ jbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at com.jthink.songkong。org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
。 db.SongCache.saveNewCoverImage(SongCache.java:332)


解决方案

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

  public static String createKeyFromData(byte [] imageData) 
{
try
{
String base64key = CharBuffer.wrap(Base64Coder.encode(getImageDataDigest(imageData)))。toString();
返回base64key;

catch(NullPointerException npe)
{
throw new RuntimeException(Unable to create filename from sum);
}
}


I'm using saveOrUpdate() when updating/creating a CoverImage object. Very occasionally I'm getting a constraint violation on the primary key.

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

It seems it is trying to create a new CoverImage (INSERT) instead of updating an existing CoverImage (UPDATE) but I don't know why because datakey is defined as the @id of the class and Im setting the datakey.

I use saveOrUpdate() rather than have separate save() and update() parts because the code is multithreaded. I actually check for the existence of the instance before calling this method and only call if the object doesn't exist so I don't expect it to already exist, but there is always the possibility as in the case. The problem seems to occur approximately about 1 in 3000 times.

Here is the Hibernate class

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");
        }
    }
}

and this is the code that uses it

   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);
    }

Full stack trace

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)

解决方案

The primary key must be unique in database, and the CoverImage's primary key is assigned by you by invoking below method. But what if there are two same imageData passed in? I am guessing a duplicated primary key would be created, which will cause 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");
    }
}

这篇关于为什么hibernate会给出ConstraintException,就好像试图在已经存在的时候创建对象一样的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆