Existe-t-il des paramètres nommés dans JDBC au lieu de paramètres positionnels, comme l'option @name
, @city
dans la requête ADO.NET ci-dessous ?
select * from customers where name=@name and city = @city
Existe-t-il des paramètres nommés dans JDBC au lieu de paramètres positionnels, comme l'option @name
, @city
dans la requête ADO.NET ci-dessous ?
select * from customers where name=@name and city = @city
JDBC ne prend pas en charge les paramètres nommés. À moins que vous ne soyez obligé d'utiliser le JDBC ordinaire (ce qui est pénible, laissez-moi vous le dire), je vous suggère d'utiliser Springs Excellent JDBCTemplate qui peut être utilisé sans l'ensemble du conteneur IoC.
NamedParameterJDBCTemplate supporte les paramètres nommés, vous pouvez les utiliser comme cela :
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);
Merci - mais je ne peux pas utiliser les ressorts, car je ne peux pas apporter autant de changements au code existant :(
L'argument de @Malax est que vous pouvez utiliser le NamedParameterJdbcTemplate à partir de Spring Standalone. Vous n'auriez pas à modifier d'autres parties du code de base.
Mais vous devez inclure de nombreux JARs Spring dans votre projet, juste pour utiliser quelques classes liées à NamedParameterJdbcTemplate. C'est dommage que org.springframework.jdbc.jar ne puisse pas être utilisé de manière autonome.
Pour éviter d'inclure un gros framework, je pense qu'une simple classe maison peut faire l'affaire.
Exemple de classe pour gérer les paramètres nommés :
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>();
}
Exemple d'appel de la classe :
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();
Veuillez noter que l'exemple simple ci-dessus ne permet pas d'utiliser deux fois un paramètre nommé. Il ne gère pas non plus l'utilisation du signe : entre guillemets.
J'ai utilisé le vôtre avec quelques petites modifications. ` 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(), " ?")) ;
Je pense que je vais faire quelque chose de similaire. Je pense qu'il serait plus agréable de passer outre l'indexeur pour cela.
Vanilla JDBC ne prend en charge que les paramètres nommés dans un fichier de type CallableStatement
(par exemple setString("name", name)
), et même dans ce cas, je pense que l'implémentation de la procédure stockée sous-jacente doit le supporter.
Un exemple de l'utilisation de paramètres nommés :
//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));
}
Oui, c'est vrai, mais toutes les bases de données ne supportent pas cette fonctionnalité. J'ai testé sur postgresql, cela ne fonctionne pas.
J'ai fini par créer ma propre méthode d'emballage.
dans lequel j'ai d'abord nettoyé la valeur à lier (vous pouvez trouver des exemples sur Google).
Ensuite, il suffit d'utiliser la fonction String.replace()
pour remplacer les placeHolders.
Le principal inconvénient est que vous devez vous assurer que la variable est effectivement sûre pour la liaison.
Edit : J'utilise maintenant Hibernate de Spring, bien mieux.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
0 votes
Cet article propose une mise en œuvre rapide d'une telle classe : javaworld.com/article/2077706/core-java/
0 votes
I think Oracle JDBC driver supports calling regular SQL statements with named parameters when using CallableStatement
.