You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot 3+Hibernate 6升级后调用SQL Server sp_getapplock返回-999错误求助

SpringBoot 3+Hibernate 6升级后调用SQL Server sp_getapplock返回-999错误求助

我最近把一个已经跑在生产环境的SpringBoot 2.x.x老应用,升级到了最新的v3.4.2版本。这次升级逼得我修复了一堆依赖问题,其中最关键的两个是:

  • 把Hibernate从v5.x.x版本升级到了v6.6.8-Final
  • 完成了从javax到Jakarta EE的全量迁移

这个应用里用到了SQL Server的sp_getapplock系统存储过程来实现运行时的数据库锁,按照官方要求,这个存储过程默认必须在事务内部执行。为了统一处理返回的状态码,我还把它包在了一个自定义的存储过程里,代码定义如下:

CREATE PROCEDURE sp_getapplock_wrapper @Resource NVARCHAR(255), @LockMode NVARCHAR(32), @LockTimeout as INT, @Result INT OUTPUT
  AS
  BEGIN
    EXEC @Result = Sp_getapplock @Resource = @Resource, @LockMode = @LockMode, @LockTimeout = @LockTimeout;
  END;

但升级完成后,每次调用这个包装后的存储过程,都会返回-999的错误码,完全没法正常加锁。奇怪的是,如果我把@LockOwner从默认的'Transaction'改成'Session',一切就都正常了——这说明问题肯定出在事务层面。

我翻了应用日志,看起来事务是正常开启的,不管是Java端还是数据库端都有对应的日志输出:

[nio-8081-exec-1] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [com.extoxesses.poc.core.service.CoreService.startProcess]: PROPAGATION_REQUIRED,ISOLATION_SERIALIZABLE
[nio-8081-exec-1] .i.SessionFactoryImpl$SessionBuilderImpl : Opening Hibernate Session.  tenant=null
[nio-8081-exec-1] o.h.r.j.i.LogicalConnectionManagedImpl   : `hibernate.connection.provider_disables_autocommit` was enabled.  This setting should only be enabled when you are certain that the Connections given to Hibernate by the ConnectionProvider have auto-commit disabled.  Enabling this setting when the Connections do not have auto-commit disabled will lead to Hibernate executing SQL operations outside of any JDBC/SQL transaction.
[nio-8081-exec-1] org.hibernate.internal.SessionImpl       : Opened Session [42330797-b6ac-4444-b8ed-edddb2d47029] at timestamp: 1740480200789
[nio-8081-exec-1] o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [SessionImpl(4729152PersistenceContext[entityKeys=[], collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
[nio-8081-exec-1] o.h.e.t.internal.TransactionImpl         : On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false
[nio-8081-exec-1] o.h.e.t.internal.TransactionImpl         : begin
[nio-8081-exec-1] cResourceLocalTransactionCoordinatorImpl : ResourceLocalTransactionCoordinatorImpl#afterBeginCallback
[nio-8081-exec-1] o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@71b08367]

存储过程的调用日志看起来也没问题:

[nio-8081-exec-1] c.e.poc.core.service.LockService         : Acquiring lock for id id
[nio-8081-exec-1] o.h.p.internal.ProcedureCallImpl         : Preparing procedure call : org.hibernate.sql.exec.internal.JdbcCallImpl@3b078a57
[nio-8081-exec-1] org.hibernate.SQL                        : 
    {call sp_getapplock_wrapper(?, ?, ?, ?)}
Hibernate: 
    {call sp_getapplock_wrapper(?, ?, ?, ?)}
[nio-8081-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl   : Registering statement [HikariProxyCallableStatement@1877695894 wrapping sp_executesql SQL: null]
[nio-8081-exec-1] org.hibernate.orm.jdbc.bind              : binding parameter (1:VARCHAR) <- [id]
[nio-8081-exec-1] org.hibernate.orm.jdbc.bind              : binding parameter (2:VARCHAR) <- [Exclusive]
[nio-8081-exec-1] org.hibernate.orm.jdbc.bind              : binding parameter (3:INTEGER) <- [0]
[nio-8081-exec-1] o.hibernate.result.internal.OutputsImpl  : Building Return [isResultSet=false, updateCount=-1, extendedReturn=false]
[nio-8081-exec-1] org.hibernate.orm.jdbc.extract           : extracted procedure output  parameter ([4] : [INTEGER]) - [-999]

事务的回滚/提交流程也正常执行:

[nio-8081-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl   : Releasing statement [HikariProxyCallableStatement@1877695894 wrapping sp_executesql SQL: EXEC sp_getapplock_wrapper  @P0 , @P1 , @P2 , @P3  OUT]
[nio-8081-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl   : Closing prepared statement [HikariProxyCallableStatement@1877695894 wrapping sp_executesql SQL: EXEC sp_getapplock_wrapper  @P0 , @P1 , @P2 , @P3  OUT]
[nio-8081-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl   : Releasing statement [HikariProxyCallableStatement@1877695894 wrapping sp_executesql SQL: EXEC sp_getapplock_wrapper  @P0 , @P1 , @P2 , @P3  OUT]
[nio-8081-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl   : HHH000387: ResultSet's statement was not registered
[nio-8081-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl   : Closing prepared statement [HikariProxyCallableStatement@1877695894 wrapping sp_executesql SQL: EXEC sp_getapplock_wrapper  @P0 , @P1 , @P2 , @P3  OUT]
[nio-8081-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl   : Exception clearing maxRows/queryTimeout [L'istruzione è chiusa.]
[nio-8081-exec-1] c.e.poc.core.service.LockService         : Cannot acquire lock for id id. Code from sql: -999
[nio-8081-exec-1] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction rollback
[nio-8081-exec-1] o.s.orm.jpa.JpaTransactionManager        : Rolling back JPA transaction on EntityManager [SessionImpl(4729152PersistenceContext[entityKeys=[], collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
[nio-8081-exec-1] o.h.e.t.internal.TransactionImpl         : rolling back
[nio-8081-exec-1] j.i.AbstractLogicalConnectionImplementor : Preparing to rollback transaction via JDBC Connection.rollback()
[nio-8081-exec-1] j.i.AbstractLogicalConnectionImplementor : Transaction rolled-back via JDBC Connection.rollback()
[nio-8081-exec-1] j.i.AbstractLogicalConnectionImplementor : LogicalConnection#afterTransaction
[nio-8081-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl   : Releasing JDBC resources
[nio-8081-exec-1] cResourceLocalTransactionCoordinatorImpl : ResourceLocalTransactionCoordinatorImpl#afterCompletionCallback(false)
[nio-8081-exec-1] .t.i.SynchronizationRegistryStandardImpl : SynchronizationRegistryStandardImpl.notifySynchronizationsAfterTransactionCompletion(5)
[nio-8081-exec-1] org.hibernate.internal.SessionImpl       : SessionImpl#afterTransactionCompletion(successful=false, delayed=false)
[nio-8081-exec-1] o.s.orm.jpa.JpaTransactionManager        : Closing JPA EntityManager [SessionImpl(4729152PersistenceContext[entityKeys=[], collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] after transaction
[nio-8081-exec-1] org.hibernate.internal.SessionImpl       : Closing session [42330797-b6ac-4444-b8ed-edddb2d47029]
[nio-8081-exec-1] o.h.e.jdbc.internal.JdbcCoordinatorImpl  : Closing JDBC container [org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl@ea72b31]
[nio-8081-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl   : Releasing JDBC resources
[nio-8081-exec-1] o.h.r.j.i.LogicalConnectionManagedImpl   : Closing logical connection
[nio-8081-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl   : Releasing JDBC resources
[nio-8081-exec-1] o.h.r.j.i.LogicalConnectionManagedImpl   : Logical connection closed

我还发现一个奇怪的现象:如果在调用这个存储过程之前,先执行一个repository.save()操作,存储过程就能正常返回,锁也能加上。这感觉像是事务管理有某种“惰性”机制,直到有实际的数据库写操作才会真正激活事务?

我在网上搜了一圈,没找到能直接解决问题的资料,只看到Hibernate的一个PR提到过新版本里事务管理逻辑有变化。为了方便排查,我还专门写了一个极简的POC来复现这个问题。

有没有大佬遇到过类似的问题?求指点!

备注:内容来源于stack exchange,提问作者exto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 11:48:04