14

デフォルト (オプション) の引数を持つストアド プロシージャを、引数を渡さずに呼び出そうとしていますが、機能しません。ここで説明したのと本質的に同じ問題です。

私のコード:

  SqlParameterSource in = new MapSqlParameterSource()
        .addValue("ownname", "USER")
        .addValue("tabname", cachedTableName)
        .addValue("estimate_percent", 20)
        .addValue("method_opt", "FOR ALL COLUMNS SIZE 1")
        .addValue("degree", 0)
        .addValue("granularity", "AUTO")
        .addValue("cascade", Boolean.TRUE)
        .addValue("no_invalidate", Boolean.FALSE)
        .addValue("force", Boolean.FALSE);

そして、私は例外を受け取ります:

Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Required input parameter 'PARTNAME' is missing
    at org.springframework.jdbc.core.CallableStatementCreatorFactory$CallableStatementCreatorImpl.createCallableStatement(CallableStatementCreatorFactory.java:209)

PARTNAME は、 this によると、オプションのパラメーターです。また、この手順を PARTNAME 引数なしで手動で実行できるという事実によっても確認されました。

4

6 に答える 6

6

この質問をあきらめて、オプションのパラメーターを含むすべてのパラメーターを渡すだけで、ブール引数を渡すことができないことに遭遇しました。ブール値は SQL データ型ではなく、PL/SQL のみであるためです。

したがって、私の現在の解決策は、JDBC はストアド プロシージャの実行には適していないということです。これが私がそれを回避する方法です。

  jdbcTemplate.execute(
        new CallableStatementCreator() {
           public CallableStatement createCallableStatement(Connection con) throws SQLException{
              CallableStatement cs = con.prepareCall("{call sys.dbms_stats.gather_table_stats(ownname=>user, tabname=>'" + cachedMetadataTableName + "', estimate_percent=>20, method_opt=>'FOR ALL COLUMNS SIZE 1', degree=>0, granularity=>'AUTO', cascade=>TRUE, no_invalidate=>FALSE, force=>FALSE) }");
              return cs;
           }
        },
        new CallableStatementCallback() {
           public Object doInCallableStatement(CallableStatement cs) throws SQLException{
              cs.execute();
              return null; // Whatever is returned here is returned from the jdbcTemplate.execute method
           }
        }
  );
于 2012-10-31T19:23:38.570 に答える
1

これが私が取った別のアプローチです。ユーザーが通話で提供するパラメーターの数を設定できる機能を追加しました。これらは、最初の n 個の定位置パラメーターになります。ストアド プロシージャで使用可能な残りのパラメーターは、データベースの既定値の処理を介して設定する必要があります。これにより、値を提供することを知らないコードを壊すことなく、新しいパラメーターをデフォルト値でリストの最後に追加したり、null 可能にすることができます。

SimpleJdbcCall をサブクラス化し、「maxParamCount」を設定するメソッドを追加しました。また、サブクラス化されたバージョンの CallMetaDataContext を設定するために、少し邪悪なリフレクションを使用しました。

public class MySimpleJdbcCall extends SimpleJdbcCall
{
    private final MyCallMetaDataContext callMetaDataContext = new MyCallMetaDataContext();

    public MySimpleJdbcCall(DataSource dataSource)
    {
        this(new JdbcTemplate(dataSource));
    }

    public MySimpleJdbcCall(JdbcTemplate jdbcTemplate)
    {
        super(jdbcTemplate);

        try
        {
            // Access private field
            Field callMetaDataContextField = AbstractJdbcCall.class.getDeclaredField("callMetaDataContext");
            callMetaDataContextField.setAccessible(true);

            // Make it non-final
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(callMetaDataContextField, callMetaDataContextField.getModifiers() & ~Modifier.FINAL);

            // Set field
            callMetaDataContextField.set(this, this.callMetaDataContext);
        }
        catch (NoSuchFieldException | IllegalAccessException ex)
        {
            throw new RuntimeException("Exception thrown overriding AbstractJdbcCall.callMetaDataContext field", ex);
        }
    }

    public MySimpleJdbcCall withMaxParamCount(int maxInParamCount)
    {
        setMaxParamCount(maxInParamCount);
        return this;
    }

    public int getMaxParamCount()
    {
        return this.callMetaDataContext.getMaxParamCount();
    }

    public void setMaxParamCount(int maxInParamCount)
    {
        this.callMetaDataContext.setMaxParamCount(maxInParamCount);
    }
}

私の CallMetaDataContext サブクラスでは、maxInParamCount を保存し、それを使用して、ストアド プロシージャに存在することがわかっているパラメーターのリストをトリミングします。

public class MyCallMetaDataContext extends CallMetaDataContext
{
    private int maxParamCount = Integer.MAX_VALUE;

    public int getMaxParamCount()
    {
        return maxParamCount;
    }

    public void setMaxParamCount(int maxInParamCount)
    {
        this.maxParamCount = maxInParamCount;
    }

    @Override
    protected List<SqlParameter> reconcileParameters(List<SqlParameter> parameters)
    {
        List<SqlParameter> limittedParams = new ArrayList<>();
        int paramCount = 0;
        for(SqlParameter param : super.reconcileParameters(parameters))
        {
            if (!param.isResultsParameter())
            {
                paramCount++;
                if (paramCount > this.maxParamCount)
                    continue;
            }

            limittedParams.add(param);
        }
        return limittedParams;
    }
}

パラメータの最大数を確認する以外は基本的に使い方は同じです。

SimpleJdbcCall call = new MySimpleJdbcCall(jdbcTemplate)
        .withMaxParamCount(3)
        .withProcedureName("MayProc");

小さな暴言: Spring が IOC コンテナーでよく知られているのは面白いことです。しかし、そのユーティリティ クラス内では、リフレクションに頼って依存クラスの代替実装を提供する必要があります。

于 2016-03-31T14:40:31.567 に答える