在JDBC中命名参数
在JDBC中是否有名称参数,而不是位置参数,比如下面的ADO.NET查询中的@city
, @city
?
select * from customers where name=@name and city = @city
JDBC不支持命名参数。 除非你肯定使用普通的JDBC(这会导致痛苦,让我告诉你),我会build议使用Springs Excellent 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框架,因为它有一些扩展,允许在查询中使用命名参数。
我最终创造了自己的包装方法。
-
我首先清理了被绑定的价值(您可以在Google上find示例)
-
然后使用Java的
String.replace()
方法来replaceplaceHolders。
最大的不利之处是你必须确保这个variables对绑定来说确实是安全的。
编辑:我现在只是使用Spring的Hibernate,好多了
普通的vanilla JDBC不支持命名参数。
如果您使用的是DB2,那么直接使用DB2类:
- 使用带有PreparedStatement对象的命名参数标记
- 使用具有CallableStatement对象的命名参数标记