Hibernate使用悲观锁还是乐观锁?

13

我的所有类都有一个

@Version

注解,所以我认为它们正在使用乐观锁定。

但是我在日志中发现了以下异常,似乎表明我正在使用悲观锁定。那么它是哪个呢?(我想使用乐观锁定)

update Song set acoustidFingerprint=?, acoustidId=?, album=?, albumArtist=?, albumArtistSort=?, albumSort=?, amazonId=?, arranger=?, artist=?, artistSort=?, artists=?, barcode=?, bpm=?, catalogNo=?, comment=?, composer=?, composerSort=?, conductor=?, country=?, custom1=?, custom2=?, custom3=?, custom4=?, custom5=?, discNo=?, discSubtitle=?, discTotal=?, djmixer=?, duration=?, encoder=?, engineer=?, fbpm=?, filename=?, genre=?, grouping=?, isCompilation=?, isrc=?, keyOfSong=?, language=?, lastModified=?, lyricist=?, lyrics=?, media=?, mixer=?, mood=?, musicbrainzArtistId=?, musicbrainzDiscId=?, musicbrainzOriginalReleaseId=?, musicbrainzRecordingId=?, musicbrainzReleaseArtistId=?, musicbrainzReleaseCountry=?, musicbrainzReleaseGroupId=?, musicbrainzReleaseId=?, musicbrainzReleaseStatus=?, musicbrainzReleaseType=?, musicbrainzWorkId=?, musicipId=?, occasion=?, originalAlbum=?, originalArtist=?, originalLyricist=?, originalYear=?, producer=?, quality=?, rating=?, recordLabel=?, releaseYear=?, remixer=?, script=?, subtitle=?, tags=?, tempo=?, title=?, titleSort=?, track=?, trackTotal=?, urlDiscogsArtistSite=?, urlDiscogsReleaseSite=?, urlLyricsSite=?, urlOfficialArtistSite=?, urlOfficialReleaseSite=?, urlWikipediaArtistSite=?, urlWikipediaReleaseSite=?, version=? where recNo=? and version=? [50200-172]
**org.hibernate.PessimisticLockException: Timeout trying to lock table ; SQL statement:**
update Song set acoustidFingerprint=?, acoustidId=?, album=?, albumArtist=?, albumArtistSort=?, albumSort=?, amazonId=?, arranger=?, artist=?, artistSort=?, artists=?, barcode=?, bpm=?, catalogNo=?, comment=?, composer=?, composerSort=?, conductor=?, country=?, custom1=?, custom2=?, custom3=?, custom4=?, custom5=?, discNo=?, discSubtitle=?, discTotal=?, djmixer=?, duration=?, encoder=?, engineer=?, fbpm=?, filename=?, genre=?, grouping=?, isCompilation=?, isrc=?, keyOfSong=?, language=?, lastModified=?, lyricist=?, lyrics=?, media=?, mixer=?, mood=?, musicbrainzArtistId=?, musicbrainzDiscId=?, musicbrainzOriginalReleaseId=?, musicbrainzRecordingId=?, musicbrainzReleaseArtistId=?, musicbrainzReleaseCountry=?, musicbrainzReleaseGroupId=?, musicbrainzReleaseId=?, musicbrainzReleaseStatus=?, musicbrainzReleaseType=?, musicbrainzWorkId=?, musicipId=?, occasion=?, originalAlbum=?, originalArtist=?, originalLyricist=?, originalYear=?, producer=?, quality=?, rating=?, recordLabel=?, releaseYear=?, remixer=?, script=?, subtitle=?, tags=?, tempo=?, title=?, titleSort=?, track=?, trackTotal=?, urlDiscogsArtistSite=?, urlDiscogsReleaseSite=?, urlLyricsSite=?, urlOfficialArtistSite=?, urlOfficialReleaseSite=?, urlWikipediaArtistSite=?, urlWikipediaReleaseSite=?, version=? where recNo=? and version=? [50200-172]
    at org.hibernate.dialect.H2Dialect$2.convert(H2Dialect.java:317)
    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 com.sun.proxy.$Proxy22.executeUpdate(Unknown Source)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3123)
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3021)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3350)
    at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:140)
    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:276)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
    at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:62)
    at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1182)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1611)
    at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:374)
    at com.jthink.songkong.db.SongCache.loadSongsFromDatabase(SongCache.java:58)
    at com.jthink.songkong.analyse.analyser.SongGroup.getSongs(SongGroup.java:48)
    at com.jthink.songkong.analyse.analyser.MergeMusicBrainzMatches.matchToMissingTracks(MergeMusicBrainzMatches.java:318)
    at com.jthink.songkong.analyse.analyser.MergeMusicBrainzMatches.call(MergeMusicBrainzMatches.java:105)
    at com.jthink.songkong.analyse.analyser.MergeMusicBrainzMatches.call(MergeMusicBrainzMatches.java:40)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:722)
Caused by: org.h2.jdbc.JdbcSQLException: Timeout trying to lock table ; SQL statement:
update Song set acoustidFingerprint=?, acoustidId=?, album=?, albumArtist=?, albumArtistSort=?, albumSort=?, amazonId=?, arranger=?, artist=?, artistSort=?, artists=?, barcode=?, bpm=?, catalogNo=?, comment=?, composer=?, composerSort=?, conductor=?, country=?, custom1=?, custom2=?, custom3=?, custom4=?, custom5=?, discNo=?, discSubtitle=?, discTotal=?, djmixer=?, duration=?, encoder=?, engineer=?, fbpm=?, filename=?, genre=?, grouping=?, isCompilation=?, isrc=?, keyOfSong=?, language=?, lastModified=?, lyricist=?, lyrics=?, media=?, mixer=?, mood=?, musicbrainzArtistId=?, musicbrainzDiscId=?, musicbrainzOriginalReleaseId=?, musicbrainzRecordingId=?, musicbrainzReleaseArtistId=?, musicbrainzReleaseCountry=?, musicbrainzReleaseGroupId=?, musicbrainzReleaseId=?, musicbrainzReleaseStatus=?, musicbrainzReleaseType=?, musicbrainzWorkId=?, musicipId=?, occasion=?, originalAlbum=?, originalArtist=?, originalLyricist=?, originalYear=?, producer=?, quality=?, rating=?, recordLabel=?, releaseYear=?, remixer=?, script=?, subtitle=?, tags=?, tempo=?, title=?, titleSort=?, track=?, trackTotal=?, urlDiscogsArtistSite=?, urlDiscogsReleaseSite=?, urlLyricsSite=?, urlOfficialArtistSite=?, urlOfficialReleaseSite=?, urlWikipediaArtistSite=?, urlWikipediaReleaseSite=?, version=? where recNo=? and version=? [50200-172]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
    at org.h2.message.DbException.get(DbException.java:158)
    at org.h2.command.Command.filterConcurrentUpdate(Command.java:281)
    at org.h2.command.Command.executeUpdate(Command.java:237)
    at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:154)
    at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:140)
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
    at sun.reflect.GeneratedMethodAccessor55.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:122)
    ... 24 more
3个回答

17

这个异常是由于锁定超时导致的。

Caused by: org.h2.jdbc.JdbcSQLException: Timeout trying to lock table ;

这里可以查看解决方案。

Hibernate还提供了机制,在应用程序中实现两种类型的锁定。

您的锁定策略可以是乐观锁定或悲观锁定。

乐观锁定

乐观锁定认为多个事务可以在互不影响的情况下完成,因此它们可以在不锁定数据资源的情况下继续进行操作。在提交之前,每个事务都会验证是否有其他事务修改了它的数据。如果检查发现存在冲突的修改,则提交事务将回滚[1]。

悲观锁定

悲观锁定认为并发事务将彼此冲突,并要求在读取资源后对其进行锁定,并且只有在应用程序使用数据后才解锁。

详情请参见这里


谢谢,我会尝试使用h2 MVCC参数。但是你的回答并没有解决我的主要问题,换句话说,“为什么Hibernate似乎在使用悲观锁定,而我认为已经配置为使用乐观锁定?” - Paul Taylor
更新,刚刚发现我已经在使用MVCC或者至少尝试着使用了,因为连接URL是jdbc:h2:songkong/database;FILE_LOCK=SOCKET;MVCC=TRUE;DB_CLOSE_ON_EXIT=FALSE。 - Paul Taylor
请尝试附加;LOCK_TIMEOUT=10000,即10秒,因为默认超时非常低,即1秒或1000毫秒。 - Macrosoft-Dev
同时,org.hibernate.PessimisticLockException 表明您的应用程序正在使用悲观锁定。当发生悲观锁定冲突时,会抛出此异常。 - Macrosoft-Dev
1
那么为什么在我的类被注解为@Version(用于乐观锁定)时会使用悲观锁定呢? - Paul Taylor
这里的资源是指整个表格还是仅指行? - Anthony Vinay

13

你正在使用乐观锁定(optimistic locking),因为你的 UPDATE 语句已经表明了这一点:

where recNo=? and version=?

有关乐观锁的全部内容都在version列的存在。

PessimisticLockException会误导你,这可能是由显式或隐式的行级锁引起的。


0

很有可能,在测试环境中您会使用不同的数据库,而不是在实际环境中使用的数据库。

H2可能会产生错误,这些错误在实际数据库(如Oracle、MySQL等)上可能不会出现。这意味着即使您的代码是正确的,但H2可能会搞乱事情。

MVCC=true可以完美地工作。 同时,您应该确保在实际系统上进行完整的集成测试,以验证实际数据库的行为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接