JDBC中的命名参数[重复]

Posted

技术标签:

【中文标题】JDBC中的命名参数[重复]【英文标题】:Named parameters in JDBC [duplicate] 【发布时间】:2011-01-19 13:54:15 【问题描述】:

JDBC 中是否有命名参数而不是位置参数,例如下面 ADO.NET 查询中的@name@city

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

【问题讨论】:

本文提供了此类类的快速实现:javaworld.com/article/2077706/core-java/… I think Oracle JDBC driver supports calling regular SQL statements with named parameters when using CallableStatement. 【参考方案1】:

JDBC 不支持命名参数。除非你一定要使用普通的 JDBC(这会导致痛苦,让我告诉你)我建议使用 Springs 优秀的 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);

【讨论】:

谢谢 - 但我不能使用弹簧,因为我不能对现有的代码库做出太大的改变 :( @Malax 提出的观点是,您可以使用 Spring Standalone 中的 NamedParameterJdbcTemplate。您不必更改代码库的任何其他部分。 但是你必须在你的项目中包含很多 Spring JAR,只是为了使用一些与 NamedParameterJdbcTemplate 相关的类。可惜org.springframework.jdbc.jar不能独立使用。 解压缩 jar 文件 - 并将所需的类文件复制到项目中。瞧…… spring-jdbc 模块依赖于spring-corespring-frameworkspring-txNamedParameterJdbcTemplate 需要一些重写才能独立使用。 repo1.maven.org/maven2/org/springframework/spring-jdbc/…【参考方案2】:

您不能在 JDBC 本身中使用命名参数。您可以尝试使用 Spring 框架,因为它有一些扩展允许在查询中使用命名参数。

【讨论】:

【参考方案3】:

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

【讨论】:

是的,这是正确的,但并非所有 db 都支持此功能。我在 postgresql 上测试过,它不起作用。 是的,显然数据库必须首先支持命名参数......而且似乎 postgres 不支持。这个问题暗示他们的数据库确实支持这一点,并想了解如何在 JDBC 中使用该功能。【参考方案4】:

普通的 JDBC 不支持命名参数。

如果您使用的是 DB2,那么直接使用 DB2 类:

    Using named parameter markers with PreparedStatement objects Using named parameter markers with CallableStatement objects

【讨论】:

NamedParameterStatement 不是 Java API 中的类。 是的。这是它的链接:javaworld.com/javaworld/jw-04-2007/jw-04-jdbc.html【参考方案5】:

为了避免包含大型框架,我认为一个简单的自制类可以解决问题。

处理命名参数的类示例:

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

请注意,上面的简单示例不会处理两次使用命名参数。它也不处理使用引号内的 : 符号。

【讨论】:

我用你的做了一些小的修改。 ` 模式 findParametersPattern = Pattern.compile("(? 认为我会做类似的事情。我认为为此覆盖索引器会更好 @WillieT gist.github.com/ruseel/e10bd3fee3c2b165044317f5378c7446的代码要点 这个要点可以改进。 indexof 用于获取索引? 我还建议添加implements AutoClosable (req java7+)

以上是关于JDBC中的命名参数[重复]的主要内容,如果未能解决你的问题,请参考以下文章

C#中的命名参数和params关键字[重复]

jdbc为啥prepared statement不支持命名参数?

在 JDBC PL/SQL 块中多次使用命名参数时出错

如何使用 JDBC 调用带有命名参数的 Sybase 存储过程

Scala可变参数列表,命名参数和参数缺省

格式化字符串未使用的命名参数[重复]