Spring JDBC-Vorlage zum Aufrufen gespeicherter Prozeduren

78

Was ist der richtige Weg, um gespeicherte Prozeduren mit der modernen (ca. 2012) Spring JDBC-Vorlage aufzurufen?

Angenommen, ich habe eine gespeicherte Prozedur, die sowohl INals auch OUTParameter deklariert.

mypkg.doSomething(
    id OUT int,
    name IN String,
    date IN Date
)

Ich bin auf CallableStatementCreatorbasierende Ansätze gestoßen, bei denen wir uns explizit registrieren INund OUTParameter festlegen müssen. Betrachten Sie die folgende Methode in der JdbcTemplateKlasse:

public Map<String, Object> call(CallableStatementCreator csc, List<SqlParameter> declaredParameters)

Natürlich weiß ich, dass ich es so verwenden kann:

List<SqlParameter> declaredParameters = new ArrayList<SqlParameter>();

declaredParameters.add(new SqlOutParameter("id", Types.INTEGER));
declaredParameters.add(new SqlParameter("name", Types.VARCHAR));
declaredParameters.add(new SqlParameter("date", Types.DATE));

this.jdbcTemplate.call(new CallableStatementCreator() {

    @Override
    CallableStatement createCallableStatement(Connection con) throws SQLException {
        CallableStatement stmnt = con.createCall("{mypkg.doSomething(?, ?, ?)}");

        stmnt.registerOutParameter("id", Types.INTEGER);
        stmnt.setString("name", "<name>");
        stmnt.setDate("date", <date>);

        return stmnt;
    }
}, declaredParameters);

Was ist der Zweck, declaredParameterswenn ich sie bereits in meiner cscImplementierung registriere ? Mit anderen Worten, warum sollte ich eine Zeit abgeben müssen, in der der cscFrühling einfach con.prepareCall(sql)intern funktionieren kann ? Kann ich nicht einen von beiden anstelle von beiden übergeben?

Oder gibt es eine viel bessere Möglichkeit, gespeicherte Prozeduren (mithilfe der Spring JDBC-Vorlage) aufzurufen als die, auf die ich bisher gestoßen bin?

Hinweis: Möglicherweise finden Sie viele Fragen, die einen ähnlichen Titel zu haben scheinen, aber nicht mit diesem identisch sind.

adarshr
quelle
3
Ich kann sehen, dass diese Frage jetzt sehr beliebt ist und es bereits mehr als 2 Jahre her ist, seit sie gestellt wurde. Wenn jemand der Meinung ist, dass es nach Spring 4 eine noch schönere Möglichkeit gibt, gespeicherte Prozeduren aufzurufen, geben Sie bitte eine Antwort oder schlagen Sie eine Bearbeitung vor.
Adarshr

Antworten:

94

Es gibt verschiedene Möglichkeiten, gespeicherte Prozeduren im Frühjahr aufzurufen.

Wenn Sie CallableStatementCreatorParameter deklarieren, verwenden Sie die Standardschnittstelle von Java CallableStatement, dh registrieren Sie Parameter und legen Sie sie separat fest. Durch die Verwendung der SqlParameterAbstraktion wird Ihr Code sauberer.

Ich empfehle Ihnen zu schauen SimpleJdbcCall. Es kann folgendermaßen verwendet werden:

SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate)
    .withSchemaName(schema)
    .withCatalogName(package)
    .withProcedureName(procedure)();
...
jdbcCall.addDeclaredParameter(new SqlParameter(paramName, OracleTypes.NUMBER));
...
jdbcCall.execute(callParams);

Für einfache Verfahren können Sie verwenden jdbcTemplate‚s - updateMethode:

jdbcTemplate.update("call SOME_PROC (?, ?)", param1, param2);
Infeligo
quelle
SimpleJdbcCallscheint wirklich cool. Ich werde dies testen und Sie wissen lassen, wie es in meinem Fall gelaufen ist.
Adarshr
2
Die Aktualisierungsmethode hat bei mir nicht funktioniert. Ich habe eine schlechte SQL-Grammatikausnahme erhalten, obwohl meine Anweisung in der Datenbank einwandfrei ausgeführt wurde. SimpleJdbcCall hat sehr gut
funktioniert
Ich versuche, jdbcTemplate.update () genauso zu verwenden, wie Sie es gesagt haben, aber es wird eine Fehlermeldung angezeigt "cannot invoke update on null object".
Suleman Khan
1
@ EpicPandaForce Ich hatte NamedParameterJdbcTemplate, nicht JdbcTemplate
Alex Bitek
8
Ich weiß nicht, ob es sich um eine Oracle-spezifische Syntax handelt, aber die Syntax für Oracle lautet: jdbcTemplate.update("{ call my_schema.my_pkg.SOME_PROC (?, ?) }", param1, param2);(Beachten Sie die geschweiften Klammern).
Inanutshellus
50

Hier sind die Möglichkeiten, die gespeicherten Prozeduren von Java aus aufzurufen

1. Verwenden von CallableStatement:

 connection = jdbcTemplate.getDataSource().getConnection();
  CallableStatement callableStatement = connection.prepareCall("{call STORED_PROCEDURE_NAME(?, ?, ?)}");
  callableStatement.setString(1, "FirstName");
  callableStatement.setString(2, " LastName");
  callableStatement.registerOutParameter(3, Types.VARCHAR);
  callableStatement.executeUpdate();

Hier verwalten wir extern das Schließen der Ressource

2. Verwenden von CallableStatementCreator

 List paramList = new ArrayList();
    paramList.add(new SqlParameter(Types.VARCHAR));
    paramList.add(new SqlParameter(Types.VARCHAR));
    paramList.add(new SqlOutParameter("msg", Types.VARCHAR));

    Map<String, Object> resultMap = jdbcTemplate.call(new CallableStatementCreator() {

    @Override
    public CallableStatement createCallableStatement(Connection connection)
    throws SQLException {

    CallableStatement callableStatement = connection.prepareCall("{call STORED_PROCEDURE_NAME(?, ?, ?)}");
    callableStatement.setString(1, "FirstName");
            callableStatement.setString(2, " LastName");
            callableStatement.registerOutParameter(3, Types.VARCHAR);
    return callableStatement;

    }
    }, paramList);

3. Verwenden Sie SimpleJdbcCall:

SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate)

.withProcedureName("STORED_PROCEDURE_NAME");

Map<String, Object> inParamMap = new HashMap<String, Object>();
inParamMap.put("firstName", "FirstNameValue");
inParamMap.put("lastName", "LastNameValue");
SqlParameterSource in = new MapSqlParameterSource(inParamMap);


Map<String, Object> simpleJdbcCallResult = simpleJdbcCall.execute(in);
System.out.println(simpleJdbcCallResult);

4. Verwenden Sie die StoredProcedure-Klasse von org.springframework.jdbc.object

The Code:
First Create subclass of StoredProcedure: MyStoredProcedure

class MyStoredProcedure extends StoredProcedure {

public MyStoredProcedure(JdbcTemplate jdbcTemplate, String name) {

super(jdbcTemplate, name);
setFunction(false);

}

}

Use MyStoredProcedure to call database stored procedure:


//Pass jdbcTemlate and name of the stored Procedure.
MyStoredProcedure myStoredProcedure = new MyStoredProcedure(jdbcTemplate, "PROC_TEST");

//Sql parameter mapping
SqlParameter fNameParam = new SqlParameter("fName", Types.VARCHAR);
SqlParameter lNameParam = new SqlParameter("lName", Types.VARCHAR);
SqlOutParameter msgParam = new SqlOutParameter("msg", Types.VARCHAR);
SqlParameter[] paramArray = {fNameParam, lNameParam, msgParam};


myStoredProcedure.setParameters(paramArray);
myStoredProcedure.compile();


//Call stored procedure
Map storedProcResult = myStoredProcedure.execute("FirstNameValue", " LastNameValue");

Referenz

Sairam Kukadala
quelle
Wie würde dies aussehen, wenn ich ein mehrzeiliges Rückgabeverfahren hätte? Wäre es eine Liste von Map <String, Object> -Objekten?
Kent Bull
1
@ Kent - Du bist richtig. Es wäre List <Map <String, Object >> für mehrere Zeilen.
Sairam Kukadala
Der einfache JDBC (Option 1) scheint in diesem Zusammenhang die einfachste Option zu sein -> +1
Marmite Bomber
19

Im Allgemeinen bevorzuge ich die Erweiterung der Spring-basierten StoredProcedureKlasse, um gespeicherte Prozeduren auszuführen.

  1. Sie müssen Ihren Klassenkonstruktor erstellen und darin den Klassenkonstruktor aufrufen StoredProcedure. Dieser Superklassenkonstruktor akzeptiert den Namen der DataSource und der Prozedur.

    Beispielcode:

    public class ProcedureExecutor extends StoredProcedure {
          public ProcedureExecutor(DataSource ds, String funcNameorSPName) {
            super(ds, funcNameorSPName);
            declareParameter(new SqlOutParameter("v_Return", Types.VARCHAR, null, new SqlReturnType() {
                    public Object getTypeValue(CallableStatement cs,
                         int paramIndex, int sqlType, String typeName) throws SQLException {
                    final String str = cs.getString(paramIndex);
                    return str;
                }           
            }));    
            declareParameter(new SqlParameter("your parameter",
                    Types.VARCHAR));
            //set below param true if you want to call database function 
            setFunction(true);
            compile();
            }
    
  2. Überschreiben Sie die Ausführungsmethode des Aufrufs einer gespeicherten Prozedur wie folgt

    public Map<String, Object> execute(String someParams) {
                 final Map<String, Object> inParams = new HashMap<String, Object>(8);
                 inParams.put("my param", "some value");
                 Map outMap = execute(inParams);
                 System.out.println("outMap:" + outMap);
                 return outMap;
             }
    

Hoffe das hilft dir.

VivekDandale
quelle
1

Eine weitere Möglichkeit, eine gespeicherte Prozedur aufzurufen, ist:

sql="execute Procedure_Name ?";
Object search[]={Id};
List<ClientInvestigateDTO> client=jdbcTemplateObject.query(sql,search,new 
   ClientInvestigateMapper());

In diesem Beispiel ist 'ClientInvestigateDTO' die POJO-Klasse und 'ClientInvestigateMapper' die Mapper-Klasse. 'Client' speichert alle Ergebnisse, die Sie beim Aufrufen der gespeicherten Prozedur erhalten.

Aditee
quelle