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