如何从groovy调用参数化的sql过程

时间:2013-02-04 16:45:14

标签: java sql groovy

我正在从groovy运行一些程序:

    sql.call("{call SCHEMA.NAME_PROCEDURE($par1,$par2,$par3)}"){}

其中sql是数据库连接的实例

这很好。

现在我需要参数化SCHEMA,所以我尝试这样的事情:

    sql.call("{call ${schema}.NAME_PROCEDURE($par1,$par2,$par3)}"){}

    sql.call("{call " + schema + ".NAME_PROCEDURE($par1,$par2,$par3)}"){}

但没有成功。我不知道为什么这两个代码片段不起作用。还有一些sqlException。我做错了什么?

请帮助

编辑:

我发现了类似的问题,但仍然没有回答:

http://groovy.329449.n5.nabble.com/Calling-stored-procedures-td344943.html

4 个答案:

答案 0 :(得分:2)

为了比上述@mtk的答案更明确,请尝试更改:

sql.call("{call " + schema + ".NAME_PROCEDURE($par1,$par2,$par3)}"){}

为:

sql.call(GString.EMPTY + "{call " + schema + ".NAME_PROCEDURE($par1,$par2,$par3)}"){}

您首次尝试将无法正常工作 - 这是尝试绑定过程的名称,它将生成以下形式的SQL:

 { call ?.NAME_PROCEDURE(?,?,?) }

第二个稍微不那么明显。 Groovy SQL使用GString对象生成SQL和绑定列表。但是,因为你从一个原始字符串开始,表达式的结果将是一个原始字符串,所以传递给sql.call的内容将如下所示:

 { call schema.NAME_PROCEDURE(par1,par2,par2) }

 { call schema.NAME_PROCEDURE(${par1},${par2},${par3}) }

这是你真正想要的。如果par1-3都是数字,那么你可以使用它,但是如果它们是字符串(或者通过替换将被强制转换为字符串的其他类型),这可能不是有效的SQL,因此是你的SQL异常。

基本上是String + GString = String。 Groovy SQL需要一个GString实例,以便它可以为此查询正确设置绑定列表。

你可以通过强制字符串成为'GString'实例来解决这个问题。 GString定义为GString + String = GString。你可以在groovy控制台上看到这个:

groovy> def par1 = 1 
groovy> def par2 = 2 
groovy> def par3 = 3 
groovy> def schema = 'myschema' 
groovy> println (("{call " + schema + ".NAME_PROCEDURE($par1,$par2,$par3)}").class) 
groovy> println ((GString.EMPTY + "{call " + schema + ".NAME_PROCEDURE($par1,$par2,$par3)}").class) 

class java.lang.String
class groovy.lang.GString$2

通过强制“{call”成为GString实例,然后它将沿着'plus'调用级联,因此您可以确保Groovy SQL获得创建'正确'绑定列表/ SQL所需的输入。

答案 1 :(得分:1)

我对此并不熟悉,但只是挖掘documentation这就是我所看到的,以及可能发生的其他可能性 -

  1. 参数预期为GString,与String不同。希望它确实被转换,但是通过使用变量组合字符串并稍后将其转换为GString对象作为[GString info]

    进行显式尝试
    GString g = GString.EMPTY + normal_str_variable; 
    
  2. schema变量未设置适当的值。

  3. Sql实例可能已关闭,您可能无法正确检查。

答案 2 :(得分:0)

希望它与问题重复 Calling stored procedure from Java / JPA

但我的回答是: 请参阅代码段

//getDBUSERByUserId is a stored procedure
String getDBUSERByUserIdSql = "{call getDBUSERByUserId(?,?,?,?)}";
callableStatement = dbConnection.prepareCall(getDBUSERByUserIdSql);
callableStatement.setInt(1, 10);
callableStatement.registerOutParameter(2, java.sql.Types.VARCHAR);
callableStatement.registerOutParameter(3, java.sql.Types.VARCHAR);
callableStatement.registerOutParameter(4, java.sql.Types.DATE);

// execute getDBUSERByUserId store procedure
callableStatement.executeUpdate();

String userName = callableStatement.getString(2);
String createdBy = callableStatement.getString(3);
Date createdDate = callableStatement.getDate(4);

示例代码:

存储过程:

CREATE OR REPLACE PROCEDURE getDBUSERByUserId(
       p_userid IN DBUSER.USER_ID%TYPE,
       o_username OUT DBUSER.USERNAME%TYPE,
       o_createdby OUT  DBUSER.CREATED_BY%TYPE,
       o_date OUT DBUSER.CREATED_DATE%TYPE)
IS
BEGIN

  SELECT USERNAME , CREATED_BY, CREATED_DATE
  INTO o_username, o_createdby,  o_date 
  FROM  DBUSER WHERE USER_ID = p_userid;

END;

通过CallableStatement调用存储过程

public class JDBCCallableStatementOUTParameterExample {

    private static final String DB_DRIVER = "oracle.jdbc.driver.OracleDriver";
    private static final String DB_CONNECTION = "jdbc:oracle:thin:@localhost:1521:MKYONG";
    private static final String DB_USER = "user";
    private static final String DB_PASSWORD = "password";

    public static void main(String[] argv) {
        try {
            callOracleStoredProcOUTParameter();
        } catch (SQLException e) {
            System.out.println(e.getMessage());
        }
    }
    private static void callOracleStoredProcOUTParameter() throws SQLException {
        Connection dbConnection = null;
        CallableStatement callableStatement = null;
        String getDBUSERByUserIdSql = "{call getDBUSERByUserId(?,?,?,?)}";
        try {
            dbConnection = getDBConnection();
            callableStatement = dbConnection.prepareCall(getDBUSERByUserIdSql);
            callableStatement.setInt(1, 10);
            callableStatement.registerOutParameter(2, java.sql.Types.VARCHAR);
            callableStatement.registerOutParameter(3, java.sql.Types.VARCHAR);
            callableStatement.registerOutParameter(4, java.sql.Types.DATE);
            // execute getDBUSERByUserId store procedure
            callableStatement.executeUpdate();
            String userName = callableStatement.getString(2);
            String createdBy = callableStatement.getString(3);
            Date createdDate = callableStatement.getDate(4);
            System.out.println("UserName : " + userName);
            System.out.println("CreatedBy : " + createdBy);
            System.out.println("CreatedDate : " + createdDate);
        } catch (SQLException e) {
            System.out.println(e.getMessage());
        } finally {
            if (callableStatement != null) {
                callableStatement.close();
            }
            if (dbConnection != null) {
                dbConnection.close();
            }
        }
    }
    private static Connection getDBConnection() {
        Connection dbConnection = null;
        try {
            Class.forName(DB_DRIVER);
        } catch (ClassNotFoundException e) {
            System.out.println(e.getMessage());
        }
        try {
            dbConnection = DriverManager.getConnection(
                DB_CONNECTION, DB_USER,DB_PASSWORD);
            return dbConnection;
        } catch (SQLException e) {
            System.out.println(e.getMessage());
        }
        return dbConnection;
    }
 }

希望这可以帮到你。 感谢。

答案 3 :(得分:0)

这个问题要求常规解决方案,所以vanilla java是不合适的。这是一个使用"内联程序"的解决方案。为了更好的参数处理。 grails 2.4之后还有一个sql.callWithRows和sql.callWithAllRows可用

    def calculateTotals(map) {
    //initialize variables
    Double returnTotalOriginalOut = 0
    Double returnTotalOtherOut = 0
    Double returnTotalNetOut = 0

    def sql = new Sql(sessionFactory.currentSession.connection())
    //calculate the totals
    sql.call("""
             DECLARE
                return_orig_chgs      number := 0;
                return_non_orig_chgs  number := 0;
                return_net_inst_chgs  number := 0;
             BEGIN
               SCHEMA.NAME_PROCEDURE(id         => ${map.id},
                                     term_in        => ${map.term},
                                     orig_chgs      => return_orig_chgs,
                                     non_orig_chgs  => return_non_orig_chgs,
                                     net_inst_chgs  => return_net_inst_chgs);
             ${Sql.DOUBLE} := return_orig_chgs;
             ${Sql.DOUBLE} := return_non_orig_chgs;
             ${Sql.DOUBLE} := return_net_inst_chgs;
            END ;
    """) { return_orig_chgs, return_non_orig_chgs, return_net_inst_chgs ->
        returnTotalOriginalOut = return_orig_chgs
        returnTotalOtherOut = return_non_orig_chgs
        returnTotalNetOut = return_net_inst_chgs
    }

    def returnMap = [:]
    returnMap = [returnTotalOriginal: returnTotalOriginalOut, returnTotalOther: returnTotalOtherOut, returnTotalNet: returnTotalNetOut]
    return returnMap
}