2013-11-27 3 views
12

Ich verwende ein Groovy Skript in Mule ESB, um Ausgabeparameter von Oracle gespeicherte Prozedur (einschließlich Cursor) zu erhalten und eine Ausnahme zu erhalten.Wie bekomme ich den Cursor von Oracle mit Groovy?

Minimal Beispiel:

import groovy.sql.Sql 
import oracle.jdbc.pool.OracleDataSource 
import oracle.jdbc.driver.OracleTypes 

def ds = new OracleDataSource() 
// setting data source parameters here 

def sql = new Sql(ds) 
def data = [] 

sql.call("""declare 
result_table sys_refcursor; 
begin 

open result_table for select 1 as a from dual; 

insert into CURSOR_TEST (ID) values (1); 
commit; 

${Sql.resultSet OracleTypes.CURSOR} := result_table; 

insert into CURSOR_TEST (ID) values (2); 
commit; 

end; 
""" 
){ table -> 

    throw new RuntimeException("Never getting this exception.") 

    table.eachRow { 
    data << it.toRowResult() 
    } 
} 

sql.close() 

return data 

Fehler:


Message    : java.sql.SQLException: Closed Statement (javax.script.ScriptException) 
Code     : MULE_ERROR--2 
-------------------------------------------------------------------------------- 
Exception stack is: 
1. Closed Statement(SQL Code: 17009, SQL State: + 99999) (java.sql.SQLException) 
    oracle.jdbc.driver.SQLStateMapping:70 (null) 
2. java.sql.SQLException: Closed Statement (javax.script.ScriptException) 
    org.codehaus.groovy.jsr223.GroovyScriptEngineImpl:323 (http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/script/ScriptException.html) 
3. java.sql.SQLException: Closed Statement (javax.script.ScriptException) 

(org.mule.api.transformer.TransformerException) org.mule.module.scripting.transformer.ScriptTransformer:39 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transformer/TransformerException.html) -------------------------------------------------------------------------------- Root Exception stack trace: java.sql.SQLException: Closed Statement at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70) at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133) at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:199) + 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything) ********************************************************************************

Select von CURSOR_TEST kehrt 1 und 2.

Oracle-Serverversion: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production.

Mule-Version: 3.5.0.

Ich verwende jdbc\lib\ojdbc6.jar von Oracle-Client-Version 11.1.0.7.0.

Was mache ich falsch?

+1

Haben Sie versucht, diesen Code in einem Groovy Skript außerhalb Mule zu laufen? –

+0

@senia In einem gelöschten Kommentar haben Sie angegeben, dass Sie dieses Problem gelöst haben, indem Sie stattdessen eine Java-Implementierung verwenden. Kannst du bitte diesen Java Code als Antwort auf deine Frage posten und akzeptieren? Es gibt uns auch die Möglichkeit, herauszufinden, was mit dieser Groovy-Implementierung nicht in Ordnung war. –

+1

@DavidDossot: hier ist [mein Workaround-Beispiel] (http://pastebin.com/XWAzXCU5). Ich denke nicht, dass dies eine gute Antwort auf meine Frage ist, nur ein gutes altes Java mit ein wenig grooviger Hilfe. – senia

Antwort

1

Der folgende Code kann Ihnen helfen, Variable SYS_REFCURSOR von Oracle anonymen Block zu erhalten.

Wir sind auf ein paar wichtige Details konzentrieren:

  1. Klasse groovy.sql.Sql nicht über OutParameter entspricht, und wir machen es manuell als CURSOR_PARAMETER und es sql.call Methode übergeben
  2. Bedenken Sie, dass der Block mit {call DECLARE beginnt und endet mit END } ohne Semikolon nach END. Sonst können wir einen schlecht erkennbaren SQLException ins Gesicht bekommen.
  3. Die Fragezeichen ? innerhalb der sqlString sind Orte für Parameterbindungen. Bindungen werden in der natürlichen Reihenfolge hergestellt. In diesem Beispiel:
    • die ersten ? mit dem ersten Elemente bindet in parametersList: "abc", den Wert als Parameter IN Behandlung;
    • die zweite ? bindet mit CURSOR_PARAMETER behandelt den Wert als OUT Parameter des übergebenen Typs;
  4. Es gibt nur einen in Schließung geben nach sql.call und ResultSet rs Reihen von Cursor liefern my_cur in anonymen Block deklariert.

import groovy.sql.OutParameter 
import groovy.sql.Sql 
import oracle.jdbc.OracleTypes 

import java.sql.ResultSet 

def driver = 'oracle.jdbc.driver.OracleDriver' 
def sql = Sql.newInstance('jdbc:oracle:thin:@MY-SERVER:1521:XXX', 'usr', 'psw', driver) 

// special OutParameter for cursor type 
OutParameter CURSOR_PARAMETER = new OutParameter() { 
    public int getType() { 
     return OracleTypes.CURSOR; 
    } 
}; 

// look at some ceremonial wrappers around anonymous block 
String sqlString = """{call 
    DECLARE 
     my_cur SYS_REFCURSOR; 
     x VARCHAR2(32767) := ?; 
    BEGIN 

     OPEN my_cur 
     FOR 
     SELECT x || level AS my_column FROM dual CONNECT BY level < 10; 

     ? := my_cur; 
    END 
} 
"""; 

// the order of elements matches the order of bindings 
def parametersList = ["abc", CURSOR_PARAMETER]; 


// rs contains the result set of cursor my_cur 
sql.call(sqlString, parametersList) { ResultSet rs -> 
    while (rs.next()) { 
     println rs.getString("my_column") 
    } 
}; 
+0

Können wir hier die String-Interpolation verwenden? Ohne String-Interpolation ist es nicht besser als der [Workaround] (http://pastebin.com/XWAzXCU5). Übrigens, ich kann Ihre Lösung nicht testen. Ich habe keinen Zugriff auf Oracle DB-Instanz. – senia

+0

Das Hauptmerkmal hier ist benutzerdefinierte OutParameter, und andere Teile der Lösung sind übliche Groovy Zeug. Ich zeigte nur den kürzesten Weg, um das gewünschte Ergebnis zu erhalten. Also, ja, wir können String-Interpolation verwenden. Und ich bin sehr überrascht zu hören, dass Ihnen Oracle DB-Instanz fehlt, obwohl die Frage mit "Oracle" markiert ist. Was meinst du, was ich tun soll? – diziaq

+0

Nichts. Ich meine: Ich kann deine Antwort nicht akzeptieren, ohne zu testen. Ich werde versuchen, es nächstes Wochenende zu testen. Die Frage ist dramatisch veraltet. Es ist mehr als 3 Jahre alt. – senia