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

我在更新/创建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()部分,因为代码是multithreading的。 我实际上在调用此方法之前检查实例是否存在,并且仅在对象不存在时调用,因此我不认为它已经存在,但总是存在这种情况的可能性。 这个问题似乎大约发生在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 * 

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

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

 CoverImage.createKeyFromData(imageData) 

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

干杯!!

主键在数据库中必须是唯一的,并且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"); } }