2013-09-10 21 views
3

我在更新/創建CoverImage對象時使用saveOrUpdate()。非常偶爾,我在主鍵上遇到約束違規。爲什麼hibernate給ConstraintException就好像試圖在已經存在的時候創建對象

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

好像它試圖創建一個新的CoverImage(INSERT),而不是更新現有CoverImage(UPDATE),但我不知道爲什麼,因爲datakey被定義爲類和Im設置的@id數據鍵。

我使用saveOrUpdate()而不是單獨保存()和更新()部分,因爲代碼是多線程的。在調用這個方法之前,我實際上檢查了實例的存在,並且只在對象不存在時才調用,所以我不期望它已經存在,但總是有這種可能性。這個問題似乎約發生在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) 
+1

這是在你的多線程或你如何生成密鑰(或兩者)。發佈代碼? – Taylor

+0

@Taylor setDataKey()代碼位於上面發佈的CoverImage類中,當我提交對象時會發生異常,我會添加完整的堆棧跟蹤t試驗 –

回答

0

看起來要創建鍵入您在以下line:

CoverImage.createKeyFromData(imageData) 

可能會有碰撞發生在您用於兩個imageData對象的函數中,這有時會導致此問題,如果它只是主鍵,那麼您可以使用很多其他方法來生成primamry,可能很簡單設置一個UUID。

乾杯!

+0

我不確定碰撞是什麼意思? datakey必須是對象中的一個字段,以便通過檢查其數據來檢查圖像是否已經存在於數據庫中,因爲這應該是唯一的,所以我無法看到添加額外的基於積分的主關鍵,但即使我做了,我不認爲這會解決這裏的根本問題。 –

+0

@PaulTaylor - 通過collission我的意思是,如果函數生成相同的密鑰,我實際上不明白爲什麼你生成這個複雜的密鑰? –

+0

因此,給定一個任意圖像文件,我可以根據數據生成一個密鑰,以查看數據是否已經添加到數據庫。如果函數生成相同的密鑰,這意味着數據已經在數據庫中,我想休眠來更新而不是插入 –

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

是的,但我認爲如果我使用與數據庫中已有的主鍵相同的主鍵實例化對象,那麼當我所謂的saveOrUpdate(),然後是commit(),Hibernate會使用它已經有一個已知主鍵的事實來確定這是一個已知hibernate的對象,因此更新對象而不是創建一個新對象。或者我誤解了休眠是如何工作的? –

+0

是的。 HTTP://www.javabeat。net/2008/09/difference-between-hibernates-saveupdate-and-saveorupdate-methods/ – Taylor

+0

除了泰勒提到的內容之外,saveOrUpdate方法還會考慮實體的@version值是否爲null,如果是的話,hibernate將會插入。 – Baggio

相關問題