[英]How to call parametrize sql procedure from 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
為了比上面的@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所需的輸入。
我對此並不熟悉,但只是通過文檔挖掘這是我所看到的,以及可能發生的其他可能性 -
該參數需要是一個與String
的GString
。 希望它確實被轉換,但是通過用變量組合一個字符串然后將它轉換為GString對象作為[ GString info ]顯式嘗試
GString g = GString.EMPTY + normal_str_variable;
schema
變量未設置適當的值。
Sql實例可能已關閉,您可能無法正確檢查。
希望它是一個重復的問題從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;
}
}
希望這可以幫到你。 謝謝。
這個問題要求groovy解決方案,所以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
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.