JPQL 到 SQL 使用 Hibernate 更新查询交叉连接问题
Posted
技术标签:
【中文标题】JPQL 到 SQL 使用 Hibernate 更新查询交叉连接问题【英文标题】:JPQL to SQL using Hibernate update query cross join problem 【发布时间】:2021-08-16 22:01:41 【问题描述】:我有以下 JPQL 查询
update ObedCommand c set c.status = :newStatus, c.updatedAt = :updatedAt where c.procInfo.processId = :processId and c.status <> :oldStatus and (c.errorCode is null or c.errorCode not in :resultCodes)
用来翻译成下面的 SQL 查询
Hibernate: update eps.obed_command set status=?, updated_at=? where process_id=? and status<>? and (error_code is null or error_code not in (?))
而且过去的一切都是一种魅力。但是后来我不得不升级一些依赖版本来匹配其他模块的依赖。那是这个查询中断的时候,现在它正在被翻译成这个 SQL。
Hibernate: update eps.obed_command cross join set status=?, updated_at=? where process_id=? and status<>? and (error_code is null or error_code not in (?))
而且,正如您所料,它不起作用。我收到以下错误
org.hibernate.exception.SQLGrammarException: could not execute statement
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1614)
at myapp.ObedCommandDAO.updateNotProcessedObedCommandToNewByProcessIdAndErrorCodeNotIn(ObedCommandDAO.java:142)
at myapp.ObedCommandDAO$$FastClassBySpringCGLIB$$dacdb134.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:685)
at myapp.ObedCommandDAO$$EnhancerBySpringCGLIB$$96300c8f.updateNotProcessedObedCommandToNewByProcessIdAndErrorCodeNotIn(<generated>)
at myapp.ObedCommandDAOTest.lambda$updateNotProcessedObedCommandToNewByProcessIdAndErrorCodeNotInTest$1(ObedCommandDAOTest.java:258)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
at myapp.ObedCommandDAOTest.updateNotProcessedObedCommandToNewByProcessIdAndErrorCodeNotInTest(ObedCommandDAOTest.java:249)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:119)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.hibernate.exception.SQLGrammarException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:103)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)
at org.hibernate.hql.internal.ast.exec.BasicExecutor.doExecute(BasicExecutor.java:100)
at org.hibernate.hql.internal.ast.exec.BasicExecutor.execute(BasicExecutor.java:59)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.executeUpdate(QueryTranslatorImpl.java:454)
at org.hibernate.engine.query.spi.HQLQueryPlan.performExecuteUpdate(HQLQueryPlan.java:377)
at org.hibernate.internal.SessionImpl.executeUpdate(SessionImpl.java:1420)
at org.hibernate.query.internal.AbstractProducedQuery.doExecuteUpdate(AbstractProducedQuery.java:1623)
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1605)
... 63 more
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "cross"
position: 25
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2497)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2233)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:310)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:446)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:370)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:149)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:124)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
... 70 more
我尝试降级多个依赖项,包括 hibernate 和 spring-data-jpa 相关的依赖项,但没有帮助。因此,如果有人能帮助我解决这个错误,我将不胜感激。
谢谢!
【问题讨论】:
【参考方案1】:也许你正在经历的就是这个https://hibernate.atlassian.net/browse/HHH-13177
如果是这种情况,您应该将查询更改为此
update ObedCommand AS c set c.status = :newStatus, c.updatedAt = :updatedAt where c.procInfo.processId = :processId and c.status <> :oldStatus and (c.errorCode is null or c.errorCode not in :resultCodes)
编辑。 尝试下一个使用子查询的方法
update ObedCommand AS c
set c.status = :newStatus,
c.updatedAt = :updatedAt
where c.procInfo.id in (select pi.id from ProcInfo pi where processId = :processId and c.procInfo.id = pi.id)
and c.status <> :oldStatus
and (c.errorCode is null or c.errorCode not in :resultCodes)
也许您必须将 ProcInfo 更改为正确的实体名称
【讨论】:
我尝试了你的解决方案,但我仍然有同样的错误。我也尝试完全删除“c”前缀,它也没有帮助。这很令人沮丧,因为它看起来真的很像我的情况 @SimonRusinov 我添加了一个新的查询建议 嗯,是的,这个有效。但我认为你误解了我的问题。我不是在寻找通过更改查询本身来使其工作的解决方案,如果我愿意,我可以将其重写为本机查询以使其工作。我的问题更像是“为什么它过去可以工作,而现在却不行?”因为我真的不想重写所有使用这种结构的查询。我宁愿找到一种方法让它们像现在一样工作。我的意思是他们不是错误的查询。那么我应该向 Hibernate 填写错误报告吗? 您在使用 postgresql 时是否也在使用它?过去使用什么休眠版本,您现在使用什么休眠版本?以上是关于JPQL 到 SQL 使用 Hibernate 更新查询交叉连接问题的主要内容,如果未能解决你的问题,请参考以下文章