H2:如何创建没有参数的存储过程

Posted

技术标签:

【中文标题】H2:如何创建没有参数的存储过程【英文标题】:H2: How to create a stored procedure with out parameters 【发布时间】:2018-01-05 21:31:29 【问题描述】:

我正在尝试在使用 Spring(非引导)配置的 JUnit 测试中创建不带参数的存储过程。我从文档和示例中了解到,我必须为静态方法设置别名才能响应存储过程调用。但是,我找不到关于它如何与out parameters 一起使用的信息。静态方法的方法签名中有什么内容?

package com.example;

import static java.sql.Types.INTEGER;

import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.h2.tools.SimpleResultSet;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes =  H2tests.TestConfiguration.class )
public class H2tests 

    @Autowired
    DataSource dataSource;

    public static ResultSet executeMyProc(int a) 

        return new SimpleResultSet();
    

    // what should the type of the second parameter be?
    public static ResultSet executeMyProc(int a, int b) 

        return new SimpleResultSet();
    

    @Test // passes
    public void worksWithInParam() throws SQLException 

        final CallableStatement stmt = dataSource.getConnection().prepareCall("CALL my_proc(?)");
        stmt.setInt(1, 44);
        stmt.executeQuery();
    

    @Test // fails
    public void worksWithOutParam() throws SQLException 

        final CallableStatement stmt = dataSource.getConnection().prepareCall("CALL my_proc(?, ?)");
        stmt.setInt(1, 999);
        stmt.registerOutParameter(2, INTEGER);
        stmt.executeQuery();
    

    public static class TestConfiguration 

        @Bean
        public DataSource dataSource() throws SQLException 

            final EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
            final EmbeddedDatabase db = builder //@formatter:off
                    .setType(EmbeddedDatabaseType.H2)
                    .setName("MODE=mysql")
                    .build(); //@formatter:on
            db.getConnection().prepareStatement("CREATE ALIAS my_proc FOR \"com.example.H2tests.executeMyProc\"")
                    .execute();
            return db;
        
    

【问题讨论】:

我的回答可能有点离题,但在我们的项目中,我们放弃了 H2 以支持 TestContainers 库 (github.com/testcontainers/testcontainers-java)。该库在 Docker 容器中运行实际数据库(在您的情况下为 MySQL),您可以访问您需要的所有功能,而不必为 H2 限制寻找解决方法。因此,如果您有机会使用 Docker,我肯定会建议您看看 TestContainers。 感谢您的意见。不幸的是,我对构建过程没有足够的影响力来实现这一点。我需要使用 H2 或类似的东西,将模拟数据库保留在 Java 进程中。 现在我正在考虑它 - 是什么阻止您使用 SQL 定义存储过程? Igor,我认为 H2 中也不存在这样的功能。在 Java 中实现它们似乎是在 H2 中存储过程的预期方式。 【参考方案1】:

我认为 H2 不支持 out 参数。您必须通过结果集返回值:

public static ResultSet hello(String name)

    SimpleResultSet result = new SimpleResultSet();
    result.addColumn("GREETING", Types.VARCHAR, 255, 0);
    result.addRow("Hello, " + name + "!");
    return result;


@Test
public void test() throws Exception

    Connection connection = DriverManager.getConnection("jdbc:h2:mem:");
    Statement statement = connection.createStatement();
    statement.execute("CREATE ALIAS hello FOR \"DatabaseTest.hello\"");
    ResultSet resultSet = statement.executeQuery("CALL hello('Bart')");
    assertThat(resultSet.next(), is(true));
    assertThat(resultSet.getString("GREETING"), is("Hello, Bart!"));

【讨论】:

恐怕结果集已被用于返回重要信息。 db 团队非常坚持我们为此使用 out 参数。您是否可以提供不支持该功能的结论的来源? 他们在roadmap...中有“支持用户自定义过程中的 OUT 参数”...

以上是关于H2:如何创建没有参数的存储过程的主要内容,如果未能解决你的问题,请参考以下文章

在H2数据库的嵌套集中创建存储过程添加节点

为啥 H2 在存储过程中的行继续“\”处犹豫不决?

mysql中如何创建存储过程

oracle存储过程中参数datatable如何接收,求高手!

Sql server2012存储过程参数传递null值,如何判定这个参数是null

带有输出变量的存储过程示例