如何使用 Spring Data JPA 和 Hibernate 执行 H2 存储过程?

2024-01-10

我想使用 Spring Data JPA 和 Hibernate 来执行一个简单的 H2 数据库存储过程。

存储过程类:

public class H2StoredProcedures {
    public static String stringIn(final String inValue) {
        log.info("stringIn: '{}'", inValue);
        return inValue + "_result";
    }
}

存储过程别名:

DROP ALIAS IF EXISTS STRING_IN;
CREATE ALIAS STRING_IN FOR "H2StoredProcedures.stringIn";

在 H2 控制台中执行按预期工作:

CALL STRING_IN('fooIn');
PUBLIC.STRING_IN('fooIn')  
fooIn_result
(1 row, 1 ms)

Spring Data JPA 存储库类:

@Procedure("STRING_IN")
String stringIn(@Param("inValue") final String inValue);

存储库测试:

@Test
public void testStringIn() throws Exception {
    assertEquals("fooIn_result", this.testRepository.stringIn("fooIn"));
}

产生以下输出:

2015-08-31 14:52:38,117 WARN  [main]: HHH000456: Named parameters are used for a callable statement, but database metadata indicates named parameters are not supported. [logger=org.hibernate.procedure.internal.ProcedureCallImpl, mdc={}]
Hibernate: {call STRING_IN(?,?)}
2015-08-31 14:52:38,119 INFO  [main]: AtomikosNonXADataSourceBean 'adminDataSource1': getConnection ( null )... [logger=com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean, mdc={}]
2015-08-31 14:52:38,128 WARN  [main]: Error delegating 'prepareCall' call [logger=com.atomikos.jdbc.JdbcConnectionProxyHelper, mdc={}]
org.h2.jdbc.JdbcSQLException: Method "STRING_IN (H2StoredProcedures, parameter count: 2)" not found; SQL statement:
 call STRING_IN(?,?)  [90087-187]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
    at org.h2.message.DbException.get(DbException.java:179)
    at org.h2.message.DbException.get(DbException.java:155)
    at org.h2.engine.FunctionAlias.findJavaMethod(FunctionAlias.java:272)
    at org.h2.expression.JavaFunction.<init>(JavaFunction.java:32)
    at org.h2.command.Parser.readJavaFunction(Parser.java:2364)
    [...]
    at org.h2.server.TcpServerThread.run(TcpServerThread.java:159)
    at java.lang.Thread.run(Thread.java:745)

    at org.h2.engine.SessionRemote.done(SessionRemote.java:622)
    at org.h2.command.CommandRemote.prepare(CommandRemote.java:68)
    at org.h2.command.CommandRemote.<init>(CommandRemote.java:45)
    at org.h2.engine.SessionRemote.prepareCommand(SessionRemote.java:492)
    at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1189)
    at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:72)
    at org.h2.jdbc.JdbcCallableStatement.<init>(JdbcCallableStatement.java:52)
    at org.h2.jdbc.JdbcConnection.prepareCall(JdbcConnection.java:899)
    [...]
    at com.sun.proxy.$Proxy72.prepareCall(Unknown Source)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$1.doPrepare(StatementPreparerImpl.java:103)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:186)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareStatement(StatementPreparerImpl.java:96)
    at org.hibernate.procedure.internal.ProcedureCallImpl.buildOutputs(ProcedureCallImpl.java:407)
    at org.hibernate.procedure.internal.ProcedureCallImpl.getOutputs(ProcedureCallImpl.java:378)
    at org.hibernate.jpa.internal.StoredProcedureQueryImpl.outputs(StoredProcedureQueryImpl.java:251)
    at org.hibernate.jpa.internal.StoredProcedureQueryImpl.execute(StoredProcedureQueryImpl.java:234)
    at org.springframework.data.jpa.repository.query.JpaQueryExecution$ProcedureExecution.doExecute(JpaQueryExecution.java:299)
    [...]
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122)
    [...]
    at com.sun.proxy.$Proxy71.stringIn(Unknown Source)
    at TestRepositoryTest.testStringIn(TestRepositoryTest.java:227)
    [...]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
2015-08-31 14:52:38,131 WARN  [main]: SQL Error: 90087, SQLState: 90087 [logger=org.hibernate.engine.jdbc.spi.SqlExceptionHelper, mdc={}]
2015-08-31 14:52:38,131 ERROR [main]: Method "STRING_IN (H2StoredProcedures, parameter count: 2)" not found; SQL statement:
 call STRING_IN(?,?)  [90087-187] [logger=org.hibernate.engine.jdbc.spi.SqlExceptionHelper, mdc={}]

针对具有以下存储过程的 MS SQL Server 数据库的相同代码可以按预期工作:

CREATE PROCEDURE STRING_IN
    @InValue SYSNAME,
    @OutValue NVARCHAR(255) OUTPUT
AS 
BEGIN
    SET NOCOUNT ON;
    SET @OutValue = @InValue + '_result';
    RETURN;
END;

似乎 org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery#createStoredProcedure() 或更可能的 Hibernates org.hibernate.jpa.internal.StoredProcedureQueryImpl#registerStoredProcedureParameter(String, Class, ParameterMode) 中存在错误,其中应该了解方言。

我尝试使用 @NamedStoredProcedureQuery 和基本上每个注释组合,但我得到了基本上相同的错误,即找不到具有 2 个参数的过程。

我还尝试向 H2StoredProcedures 添加带有输入/输出参数的版本:

public static void stringInOut(final String inValue, String outValue) {
    log.info("stringInOut: '{}'", inValue);
    outValue = inValue + "_result";
}

如果我使用 String 返回类型设置 in/out 存储库方法:

@Procedure(procedureName = "STRING_IN_OUT")
String stringInOut(@Param("inValue") final String inValue, @Param("outValue") String outValue);

我得到第三个参数未找到:

2015-08-31 15:19:15,517 ERROR [main]: Method "STRING_IN_OUT (H2StoredProcedures, parameter count: 3)" not found; SQL statement:
 call STRING_IN_OUT(?,?,?)  [90087-187] [logger=org.hibernate.engine.jdbc.spi.SqlExceptionHelper, mdc={}]

如果我使用 void 返回类型设置输入/输出存储库方法:

@Procedure(procedureName = "STRING_IN_OUT")
void stringInOut(@Param("inValue") final String inValue, @Param("outValue") String outValue);

我收到一个错误,大概是尝试将结果映射到 void:

Caused by: org.hibernate.MappingException: No Dialect mapping for JDBC type: 0
    at org.hibernate.dialect.TypeNames.get(TypeNames.java:87)
    at org.hibernate.dialect.TypeNames.get(TypeNames.java:118)
    at org.hibernate.dialect.Dialect.getHibernateTypeName(Dialect.java:653)
    at org.hibernate.loader.custom.JdbcResultMetadata.getHibernateType(JdbcResultMetadata.java:93)
    at org.hibernate.loader.custom.ScalarResultColumnProcessor.performDiscovery(ScalarResultColumnProcessor.java:62)
    at org.hibernate.loader.custom.CustomLoader.autoDiscoverTypes(CustomLoader.java:498)
    at org.hibernate.result.internal.OutputsImpl$CustomLoaderExtension.processResultSet(OutputsImpl.java:297)
    at org.hibernate.result.internal.OutputsImpl.extractResults(OutputsImpl.java:152)
    at org.hibernate.result.internal.OutputsImpl.extractCurrentResults(OutputsImpl.java:143)
    at org.hibernate.result.internal.OutputsImpl.access$100(OutputsImpl.java:52)
    at org.hibernate.result.internal.OutputsImpl$CurrentReturnState.buildOutput(OutputsImpl.java:203)
    at org.hibernate.result.internal.OutputsImpl$CurrentReturnState.getOutput(OutputsImpl.java:187)
    at org.hibernate.result.internal.OutputsImpl.getCurrent(OutputsImpl.java:108)
    at org.hibernate.jpa.internal.StoredProcedureQueryImpl.execute(StoredProcedureQueryImpl.java:234)
    at org.springframework.data.jpa.repository.query.JpaQueryExecution$ProcedureExecution.doExecute(JpaQueryExecution.java:299)
    at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:77)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:100)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:91)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:393)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:371)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    ... 43 more

我做了一些调试,简短的回答是 Hibernate JPA(至少 5.0.0 及以下)不支持 H2Dialect 的存储过程。

H2Dialect 继承 Dialect.getCallableStatementSupport(),它返回 StandardCallableStatementSupport.NO_REF_CURSOR_INSTANCE。标准可调用语句支持无法正确处理 H2“out”参数,该参数是 Java 返回值而不是语句参数。我尝试扩展 H2Dialect 和 StandardCallableStatementSupport 类来创建支持 H2 可调用语句的版本。然后我在 org.hibernate.procedure.internal.ProcedureCallImpl#buildOutputs 方法中遇到了问题。此方法实现它自己的语句准备,而不是使用 CallableStatementSupport#registerParameters 方法。似乎没有一种干净的方法来扩展ProcedureCallImpl或buildOutputs,并且许多待办事项,包括“全面的概念验证!!!!!!”,并没有给我太多信心。我尝试了该类的修改版本,看看在语句中不包含输出参数是否有效。我发现虽然它调用了该过程,但它却不知道如何处理结果。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Spring Data JPA 和 Hibernate 执行 H2 存储过程? 的相关文章

  • 本机查询 (JPA) 未重置并返回相同的旧结果

    我有一个本机 sql 查询如下 for init i 0 i lt 2 i String sql Select from accounts where id Query query em createNativeQuery sql Acco
  • [PersistenceUnit:<名称>]:无法构建EntityManagerFactory

    正如主题所述 我的问题是EntityManagerFactory无法建造 我正在使用 Maven Hibernate 我正在连接到 MySQL 数据库
  • Hibernate 乐观锁..它是如何工作的?

    我正在阅读下面关于休眠乐观锁定的博客 我打算将它与休眠一起使用 但是 我有一个担忧 我们有java代码和c 代码 都连接到一个数据库 虽然java代码可以使用hibernate来实现乐观锁定 但我想让c 代码做同样的事情 此外 C 代码正在
  • 如何调试 MySQL 存储过程?

    我当前的调试存储过程的过程非常简单 我创建一个名为 debug 的表 在存储过程运行时从其中插入变量值 这允许我查看脚本中给定点的任何变量的值 但是有没有更好的方法来调试 MySQL 存储过程 下列debug msg可以调用过程来简单地将调
  • Spring 3.1 + Hibernate 4.1 Propagation.Supports 问题

    我正在将我的项目从 Spring 3 0 hibernate 3 6 x 迁移到 S3 1 H4 1 我的新代码如下
  • 一个存储过程创建的临时表可以在另一个存储过程中使用吗?

    我有一个存储过程 它使用找到的索引创建一个临时表CONTAINSTABLE就像 我放了一段存储过程代码 CREATE TABLE tmpTable ID INT RANK INT SELECT query SELECT DISTINCT I
  • 在 Intellij 中找不到 /hibernate.cfg.xml

    现在 我正在使用 IntelliJ 学习 Hibernate 因此 我创建了一个 Maven 项目并创建了一个 Hibernate 程序 但后来我遇到了像此图中所示的错误 然后我就在网上寻找解决方案 但我找不到任何正确的解决方案 If yo
  • 特定查询出现错误

    Lucene 的新手 我在 java 客户端中将它与 Hibernate 一起使用 并且在特定查询上收到此错误 HSEARCH000146 The query string a applied on field name has no me
  • JPA 中的复合主键

    EmbeddedId 或 IdClass 注释用于表示复合主键 我该如何使用不带 EmbeddedId或IdClass 的复合主键 如果可以在没有 EmbeddedId或IdClass 的情况下使用复合主键 那么我该如何使用EntityMa
  • 使用 hibernate 的多态“get”,多对一,InheritanceType.JOINED

    我有这样的东西 具有多个座位中的一个座位的汽车类别 Seat 有一个子类 LeatherSeat public class Car private Seat seat ManyToOne fetch FetchType LAZY publi
  • Hibernate在删除实体时将外键设置为null

    我有以下休眠实体 Entity Table name model view public class ModelView Id GeneratedValue strategy GenerationType AUTO Column name
  • Hibernate 每个子类一个表继承策略的效率

    我正在考虑 Hibernate 管理的类层次结构的表布局 当然 每个子类表技术在我看来是一般意义上最合适的 然而 通过逻辑思考 我对其性能有些担忧 尤其是随着子类数量的扩展 举一个非常简短 且经典 的示例 假设您有以下类 public ab
  • 如何模拟@PrePersist方法?

    如何模拟 PrePersist 方法 例如我实例化的实体的 preInit 我正在使用 TestNG EasyMock 是首选 Test enabled true public void testCreateOrder Instantiat
  • Eclipse 无法识别 persistence.xml 的内容

    我在 eclipse 中收到以下错误 persistence xml 文件没有可识别的内容 我的 persistence xml 文件在我的应用程序中工作得很好 但 eclipse 一直给我这个错误 我在移动文件并使用 m2eclipse
  • 如何在 QueryDSL 中选择文字

    我目前正在开发一个使用 queryDSL 和 hibernate 的项目 其中它需要一个选择文字 按照发布的示例here https stackoverflow com questions 18691317 querydsl how to
  • Hibernate:session.load 与 session.get

    我的印象是session load 在缓存中加载代理对象session get 总是访问数据库 但看完 JavaBrains 后我很困惑video https youtu be RmnrgocuivQ list PL4AFF70118497
  • 使用 JPA Criteria API 进行分页的总行数

    我正在系统中为实体实现 高级搜索 功能 以便用户可以使用该实体的属性上的多个条件 eq ne gt lt 等 来搜索该实体 我正在使用 JPA 的 Criteria API 动态生成 Criteria 查询 然后使用setFirstResu
  • 很好地处理数据库约束错误

    再一次 它应该很简单 我的任务是在我们的应用程序的域对象中放置一个具有唯一约束的特定字段 这本身并不是一个很大的挑战 我刚刚做了以下事情 public class Location more fields Column unique tru
  • Mysql 创建定义器

    我创建了一个在 CentOS Web 服务器上运行的 Intranet Web 应用程序 该应用程序使用另一个本地服务器 始终是 CentOS 作为 MySQL 数据库 在数据库内部我创建了例程 这些例程总是这样开始 CREATE DEFI
  • JPA中flush的确切目的是什么

    一些令人困惑的解释 冲洗 刷新是将底层持久存储与内存中保存的持久状态同步的过程 它将更新或插入到正在运行的事务中的表中 但它可能不会提交这些更改 如果无论如何更改仅在提交后才会保留在数据库中 那么为什么要在代码中间刷新呢 运行刷新后 如果对

随机推荐

  • 移除观察员是强制性的(必要的)吗?

    有一个观察者 我在整个应用程序生命周期中都需要它 我应该删除它吗 我认为GC应用程序关闭后将删除它 对吗 如果是的话 我什么时候删除它 在deinit 如果您为 iOS 8 及之前版本提供支持 你必须移除里面的观察者dealloc or v
  • Google 地图实用程序 IOS Pod 错误

    我在使用 pod 将 Google Maps IOS 实用程序 用于标记聚类 添加到我的 swift xcode 项目中时遇到问题 当我跑步时pod install它失败并出现以下错误 Pods App 目标具有传递依赖关系 其中包括静态
  • 我的 IP 在 PHP 主服务器中显示错误

    好吧 足够简单 好吧 也许不是 我的 IP 目前是72 184 212 85然而 上面我在脚本的 IP 阻止系统上使用的代码将我的 IP 显示为我的家庭服务器 IP127 0 0 1 因此 当我转到脚本时 我的 IP 显示为127 0 0
  • 在 Android 上获取 OAuth2 令牌时 UNREGISTERED_ON_API_CONSOLE

    我们使用 Android Jellybean 及更高版本 并且我们有一个应用程序需要使用 OAuth2 与 Google 进行身份验证 我简化了登录活动 但它看起来像这样 AccountManager mAccountManager Acc
  • 在 npm 脚本中运行 2 个命令(nodemon && sass --watch)

    我有一个 package json 文件 如下所示 scripts test echo Error no test specified exit 1 start node src app js dev nodemon src app js
  • 我应该在 Windows 消息框中使用警告图标还是问号图标?

    许多人都知道MessageBoxIcon类型为 问题 如果你对这个图标不是特别熟悉 它只是一个美化的问号 我很好奇这个图标在专业应用程序中是否可以接受 例如 假设我有一个按钮 单击该按钮将清除整个表单上的所有文本字段 单击按钮时 我想警告用
  • 是否可以为气泡图制作图例?

    目前 互联网上没有使用 dc js 和 dc legend 函数的带有图例的气泡图的示例 that sessions scatterplot width 830 height 350 transitionDuration 1000 marg
  • 属性列表还是继承丛林?

    我有 2 个应用程序 我们称它们为 AppA 和 AppB 相互通信 AppA 正在向 AppB 发送对象 可能有不同的对象 AppB 并不支持每个对象 一个对象可以是一个模型 想象一下游戏 其中模型是车辆 房屋 人等 可能有不同的 App
  • 铬中的 SQLite

    是否可以制作像 Firefox 扩展一样与 sqlite 数据库交互的 chrome 扩展 您能给我一些建议或链接吗 哪里有关于开发与 sqlite 交互的 chrome 扩展的更多信息 谢谢 您可以使用网络 SQL API http de
  • 如何在 PrimeFaces 的工具提示上显示错误消息时摆脱空工具提示?

    我在某处显示错误消息
  • 如何在 R 中重置 par(mfrow)

    我设置了 par mfrow c 1 2 现在每次我绘制它时 它都会显示将其分成 2 个图 我怎样才能将其重置为仅显示一个图 非常感谢 您可以重置 mfrow 参数 par mfrow c 1 1
  • 阻止垃圾邮件发送者创建帐户(reCaptcha 不起作用)

    您好 我们刚刚在我们的电子邮件系统中注意到一堆尼日利亚垃圾邮件帐户 现在 我们的注册表单中确实有一个 reCaptcha 但显然他们手动或以其他方式绕过了它 这似乎是一种半手动规避 因为帐户不是批量创建的 而是以中间间隔几分钟的方式源源不断
  • enable_if:不带参数的 void 成员函数的最小示例

    我正在努力更好地理解std enable if在 C 11 中 并一直在尝试编写一个最小的示例 一个类A具有成员函数void foo 根据类型有不同的实现T来自类模板 下面的代码给出了所需的结果 但我还没有完全理解它 为什么版本V2工作 但
  • Double 数据类型,计算小数位后的小数

    下面的方法应该返回 这个 双精度 值有多少小数精度 尾随数字的数量 的答案 当值看起来像 5900 43 5900 043 等等时 我就猜对了 当该方法收到 5900 00 时 它返回 0 这是错误的 在我的需要中
  • 从单独的线程访问表单的控件

    我正在练习线程并遇到这个问题 情况是这样的 我在一个表单上有 4 个进度条 一个用于下载文件 一个用于显示页面加载状态等 我必须从单独的线程控制每个 ProgressBar 的进度 问题是我得到了无效操作异常其中说 跨线程操作无效 控制 p
  • 按引用传递引用与按值传递引用 - C#

    问候 我明白了按值传递和按引用传递之间的区别 但是通过 ref 传递引用 例如数组 和通过值传递数组是我似乎无法理解的 如何通过引用传递引用 int myArray 1 2 3 PassByVal myArray PassByRef ref
  • 什么时候不应该使用 React 备忘录?

    我一直在玩React 16 6 0最近我喜欢这个想法反应备忘录 但我一直无法找到有关最适合实现它的场景的任何内容 React 文档 https reactjs org docs react api html reactmemo https
  • 使用后置变量传递表数据

    基本上我有一个表 其中包含来自数据库的一堆数字 其中包含总计 小计列 我不打算将任何总数添加到数据库中 但我需要将总数从一页传递到下一页 我似乎无法使用 PHP 将它们作为后置变量正确传递 我想知道这是否是一个糟糕的策略 其次我应该做什么
  • 如何为角度反应形式的自定义验证器编写单元测试用例?

    我有一个自定义模型驱动的表单验证器来验证最大文本长度 export function maxTextLength length string return function control FormControl const maxLeng
  • 如何使用 Spring Data JPA 和 Hibernate 执行 H2 存储过程?

    我想使用 Spring Data JPA 和 Hibernate 来执行一个简单的 H2 数据库存储过程 存储过程类 public class H2StoredProcedures public static String stringIn