如何使用 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 存储过程? 的相关文章

  • SQL Server 存储过程对象名称无效

    我在尝试修改现有存储过程时收到此错误 Invalid object name dbo BackupDB 我能够创建此存储过程 但是当我单击修改选项来修改此存储过程时 系统显示了上述错误 您会看到所附图片 当尝试执行此命令时 我也遇到同样的错
  • 不想保留一对一的实体

    假设我有两节课Employee and Department In Employee我已经写了 OneToOne fetch FetchType EAGER cascade CascadeType ALL JoinColumn name d
  • 混合参数策略 - 仅使用命名策略、位置策略或 JPA 序数策略之一

    我正在从 Oracle 数据库调用函数并面临以下异常 org hibernate engine query ParameterRecognitionException 混合参数策略 仅使用命名 位置或 JPA 序数策略之一 这是我的用户 j
  • 如何更改 Hibernate CharacterTypeDescriptor 以处理空列值

    我们的问题是我们无法获取数据 其中包括empty长度为 0 的字符串 来自旧数据库 由于StringIndexOutOfBoundsExceptiion源自Hibernate的CharacterTypeDescriptor 我们希望更改 H
  • 存储过程函数中的动态表名

    我编写了一个存储过程函数来从表中获取名称 问题是我希望将表名作为参数传入 有几个不同的表我需要使用此函数 DELIMITER CREATE DEFINER root localhost FUNCTION getName tableName
  • FetchType.LAZY 不适用于休眠中的 @ManyToOne 映射

    简而言之 我的 Child 类与 Parent 类之间存在多对一的关系 我想加载所有的孩子 而不必加载他们的父母详细信息 我的孩子班级是 Entity public class Child implements Serializable I
  • JpaRepository 上的@Transactional

    我正在使用只读数据库将一些数据输入到我的项目中 我们使用带有 jpa 和 hibernate 的 Spring v3 以下注释是否会使对我的存储库的所有调用成为只读事务 或者我是否需要调用存储库的服务层上的注释 package com bl
  • 如何将变量设置为触发器 MYSQL 内存储过程的结果?

    我这里有一个小问题 我正在为我的数据库工作创建一个触发器 但我不知道如何在触发器内使用存储过程 我想将过程的结果保存在变量中 然后使用稍后在 IF 比较器上变量 这是我的代码 DELIMITER CREATE TRIGGER insert
  • H2数据库:如何进行加密保护,而不暴露文件加密密钥

    我们在服务器模式下使用Java H2数据库 因为我们不希望用户访问数据库文件 为了对数据库文件添加更多保护 我们计划使用 AES 加密 将 CIPHER AES 添加到数据库 URL 以防存储被盗 但是 每个用户在连接时还需要提供文件保护密
  • 未注入带有 JPA2 的 Apache Ignite 2.7 IgniteRepository

    使用在 Web 上建立的 guildes 我使用 Spring Data JPA 2 应用程序制作了简单的 Spring Boot 2 仅在 2 7 版本中才向 Apache Ignite 添加了 Spring Boot JPA 2 支持
  • Hibernate 标准接受 %% 值

    我正在使用下面的 Hibernate 代码来过滤workFlowName crt add Restrictions like workFlowName workFlow MatchMode ANYWHERE crt is the crite
  • 如何使用 Spring Data 和 QueryDSL 执行带分页的 JPAQuery

    我有这个请求 可以很好地处理queryDSL Iterable
  • 为什么 hibernate 在一张表中保存两个 @OneToMany 列表?

    想象一下使用 Hibernate 和 JPA 的简化代码如下 Entity class C Id GeneratedValue public long id MappedSuperclass abstract class A Id Gene
  • 实体创建无用的 id 字段

    我有一个CrudRepository与两个实体 Problem 特征实体总是创建一个附加的id数据库中的字段但未选择正确的characteristic id要生成的字段JSON machine entity machine id name
  • 使用 Hibernate 和 Apache DBCP 的 MySQL 连接池问题

    看来我的应用程序有问题 当应用程序在启动后闲置很长时间 我不确定确切的时间 时 我会在日志中收到以下错误消息 我使用 Spring Hibernate MySQL 和 ApacheDBCP 进行连接池 ERROR org hibernate
  • Hibernate hbm2ddl.auto=update 不更新 MySQL 中的列定义

    我正在尝试使用 hbm2ddl auto update 更新现有表 多个表中有多个列 其中数据库列定义与实体中的声明发生了变化 喜欢 Column name mycolumn nullable false length 10 private
  • 如何为连接表中的其他属性创建多对多 Hibernate 映射?

    我需要一个多对多的休眠映射需要 3 个连接 我试图找到一个没有中间实体的解决方案 例如LecturerCourse 我的数据库中的讲师和课程表之间存在多对多关系 一门课程可以由多名讲师讲授 而一名讲师可以讲授多门课程 我事先存储了课程 但是
  • 从存储过程中的动态 SQL 获取结果

    我正在编写一个存储过程 需要在过程中动态构造 SQL 语句以引用传入的表名称 我需要让这个 SQL 语句返回一个结果 然后我可以在整个过程的其余部分中使用该结果 我尝试过使用临时表和所有内容 但我不断收到一条消息 提示我需要声明变量等 例如
  • 如何在 HQL 中编写 Like 查询

    我想搜索以特定字母开头的特定字符串 因此 例如如果起始字母是 A 那么它应该产生一个结果 其中包含所有带有字母的字符串 A 我该如何实现这一目标 我的查询如下所示 Query qry session createQuery From Reg
  • 通过条件查询获取表的第一行

    如何使用以下命令获取表格的第一行criteria or HQL query 表创建脚本 CREATE TABLE MonthlySubscriber MSISDN bigint 20 NOT NULL MonthOfYear int 11

随机推荐

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

    有一个观察者 我在整个应用程序生命周期中都需要它 我应该删除它吗 我认为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