Именованные параметры в JDBC


есть ли именованные параметры в JDBC вместо позиционных, таких как @name,@city в ADO.NET запрос ниже?

select * from customers where name=@name and city = @city
6 55

6 ответов:

JDBC не поддерживает именованные параметры. Если вы не связаны с использованием простого JDBC (что вызывает боль, позвольте мне сказать вам, что) я бы предложил использовать пружины отличные JDBCTemplate, которые могут быть использованы без всего контейнера IoC.

NamedParameterJDBCTemplate поддерживает именованные параметры, вы можете использовать их так:

 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);

чтобы избежать включения большой структуры, я думаю, что простой самодельный класс может сделать трюк.

пример класса для обработки именованных параметров:

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>();
}

пример вызова класс:

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();

обратите внимание, что выше простой пример не обрабатывает, используя два параметра. Он также не обрабатывает использование: знак внутри кавычек.

Vanilla JDBC поддерживает только именованные параметры в CallableStatement (например,setString("name", name)), и даже тогда я подозреваю, что базовая реализация хранимой процедуры должна поддерживать ее.

пример использования именованных параметров:

//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));
}

вы не можете использовать именованные параметры в самом JDBC. Вы можете попробовать использовать Spring framework, так как он имеет некоторые расширения, которые позволяют использовать именованные параметры в запросах.

Я закончил тем, что просто создал свою собственную обертку meothod.

  1. в котором я сначала санировал привязанное значение (вы можете найти примеры в Google)

  2. тогда просто использовал Java String.replace() метод для замены заполнителей.

самое большое падение заключается в том, что вы должны убедиться, что переменная действительно безопасна для привязки.

Edit: теперь я просто использую весеннюю спячку, много лучше

обычный ванильный JDBC не поддерживает именованные параметры.

Если вы используете DB2, то используйте классы DB2 напрямую:

  1. использование именованных маркеров параметров с объектами PreparedStatement
  2. использование именованных маркеров параметров с объектами CallableStatement