Benannte Parameter in JDBC [Duplikat]

75

Gibt es Parameter in JDBC anstelle von Positions diejenigen genannt, wie die @name, @cityin der ADO.NET Abfrage unten?

select * from customers where name=@name and city = @city
Fakrudeen
quelle
Dieser Artikel hier bietet eine schnelle Implementierung einer solchen Klasse: javaworld.com/article/2077706/core-java/…
Sorin Postelnicu
I think Oracle JDBC driver supports calling regular SQL statements with named parameters when using CallableStatement.
Alex78191

Antworten:

75

JDBC unterstützt keine benannten Parameter. Sofern Sie nicht an die Verwendung von einfachem JDBC gebunden sind (was Schmerzen verursacht, lassen Sie mich das sagen), würde ich die Verwendung von Springs Excellent JDBCTemplate empfehlen, das ohne den gesamten IoC-Container verwendet werden kann.

NamedParameterJDBCTemplate unterstützt benannte Parameter. Sie können sie folgendermaßen verwenden:

 NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);

 MapSqlParameterSource paramSource = new MapSqlParameterSource();
 paramSource.addValue("name", name);
 paramSource.addValue("city", city);
 jdbcTemplate.queryForRowSet("SELECT * FROM customers WHERE name = :name AND city = :city", paramSource);
Malax
quelle
Danke - aber ich kann keine Federn verwenden, weil ich nicht so viel an der vorhandenen Codebasis ändern kann :(
Fakrudeen
2
Der Punkt, den @Malax macht, ist, dass Sie das NamedParameterJdbcTemplate von Spring Standalone aus verwenden können. Sie müssten keine anderen Teile der Codebasis ändern.
Gareth Davis
11
Sie müssen jedoch viele Spring-JARs in Ihr Projekt aufnehmen, um nur einige Klassen zu verwenden, die sich auf die NamedParameterJdbcTemplate beziehen. Es ist schade, dass org.springframework.jdbc.jar nicht eigenständig verwendet werden kann.
Xmedeko
3
Entpacken Sie die JAR-Datei - und kopieren Sie die gewünschten Klassendateien in Ihr Projekt. Voila ..
Lars Juel Jensen
6
das spring-jdbcModul ist abhängig von spring-core, spring-framework, und spring-tx. NamedParameterJdbcTemplatewürde ein Umschreiben erfordern, um Standalone zu verwenden. repo1.maven.org/maven2/org/springframework/spring-jdbc/…
jordanpg
33

Um ein großes Framework zu vermeiden, kann meiner Meinung nach eine einfache hausgemachte Klasse den Trick machen.

Beispiel einer Klasse zur Behandlung benannter Parameter:

public class NamedParamStatement {
    public NamedParamStatement(Connection conn, String sql) throws SQLException {
        int pos;
        while((pos = sql.indexOf(":")) != -1) {
            int end = sql.substring(pos).indexOf(" ");
            if (end == -1)
                end = sql.length();
            else
                end += pos;
            fields.add(sql.substring(pos+1,end));
            sql = sql.substring(0, pos) + "?" + sql.substring(end);
        }       
        prepStmt = conn.prepareStatement(sql);
    }

    public PreparedStatement getPreparedStatement() {
        return prepStmt;
    }
    public ResultSet executeQuery() throws SQLException {
        return prepStmt.executeQuery();
    }
    public void close() throws SQLException {
        prepStmt.close();
    }

    public void setInt(String name, int value) throws SQLException {        
        prepStmt.setInt(getIndex(name), value);
    }

    private int getIndex(String name) {
        return fields.indexOf(name)+1;
    }
    private PreparedStatement prepStmt;
    private List<String> fields = new ArrayList<String>();
}

Beispiel für den Aufruf der Klasse:

String sql;
sql = "SELECT id, Name, Age, TS FROM TestTable WHERE Age < :age OR id = :id";
NamedParamStatement stmt = new NamedParamStatement(conn, sql);
stmt.setInt("age", 35);
stmt.setInt("id", 2);
ResultSet rs = stmt.executeQuery();

Bitte beachten Sie, dass das obige einfache Beispiel die zweimalige Verwendung des benannten Parameters nicht behandelt. Es funktioniert auch nicht mit dem: -Zeichen in Anführungszeichen.

InvulgoSoft
quelle
Ich habe deine mit ein paar kleinen Modifikationen benutzt. `Pattern findParametersPattern = Pattern.compile (" (? <! ') (: [\\ w] *) (?!') "); Matcher matcher = findParametersPattern.matcher (statementWithNames); while (matcher.find ()) {fields.add (matcher.group (). substring (1)); } prepStmt = conn.prepareStatement (statementWithNames.replaceAll (findParametersPattern.pattern (), "?"));
WillieT
Ich denke, ich werde etwas Ähnliches tun. Ich denke, es wäre besser, den Indexer dafür zu überschreiben
JonnyRaa
@ WillieT Pattern (?!\\B'[^']*)(:\\w+)(?![^']*'\\B)funktioniert besser für mich.
Furgas
1
Kern für Code von @WillieT gist.github.com/ruseel/e10bd3fee3c2b165044317f5378c7446
Ruseel
1
dieser Kern könnte sich gut verbessern. indexof um den Index zu bekommen?
mmm
23

Vanilla JDBC unterstützt nur benannte Parameter in einem CallableStatement(z. B. setString("name", name)), und selbst dann vermute ich, dass die zugrunde liegende Implementierung gespeicherter Prozeduren dies unterstützen muss.

Ein Beispiel für die Verwendung benannter Parameter:

//uss Sybase ASE sysobjects table...adjust for your RDBMS
stmt = conn.prepareCall("create procedure p1 (@id int = null, @name varchar(255) = null) as begin "
        + "if @id is not null "
        + "select * from sysobjects where id = @id "
        + "else if @name is not null "
        + "select * from sysobjects where name = @name "
        + " end");
stmt.execute();

//call the proc using one of the 2 optional params
stmt = conn.prepareCall("{call p1 ?}");
stmt.setInt("@id", 10);
ResultSet rs = stmt.executeQuery();
while (rs.next())
{
    System.out.println(rs.getString(1));
}


//use the other optional param
stmt = conn.prepareCall("{call p1 ?}");
stmt.setString("@name", "sysprocedures");
rs = stmt.executeQuery();
while (rs.next())
{
    System.out.println(rs.getString(1));
}
Skaffman
quelle
5
Ja, es ist richtig, aber nicht alle DBs unterstützen diese Funktion. Ich habe auf postgresql getestet, es funktioniert nicht.
Den Bardadym
1
Ja, natürlich muss die Datenbank zuerst benannte Parameter unterstützen ... und es scheint, dass postgres dies nicht tut. Die Frage impliziert, dass ihre Datenbank dies unterstützt und verstehen möchte, wie die Funktion in JDBC verwendet wird.
Hotel
1

Sie können benannte Parameter nicht in JDBC selbst verwenden. Sie können versuchen, das Spring-Framework zu verwenden, da es einige Erweiterungen enthält, die die Verwendung benannter Parameter in Abfragen ermöglichen.

Ivan Vrtarić
quelle