什么是使用JDBC来参数化IN子句的最佳方法?

说我有一个forms的查询

SELECT * FROM MYTABLE WHERE MYCOL in (?) 

我想参数化参数。

有没有一种简单的方法可以在Java中使用JDBC执行此操作,而且可以在不修改SQL本身的情况下在多个数据库上工作?

我发现最接近的问题与C#有关 ,我想知道是否有什么不同的Java / JDBC。

在JDBC中确实没有直接的方法。 某些 JDBC驱动程序似乎支持IN子句中的PreparedStatement#setArray() 。 我只是不确定哪些是。

您可以使用String#join()Collections#nCopies()辅助方法为IN子句生成占位符,并使用PreparedStatement#setObject()设置另一个辅助方法来设置循环中的所有值。

 public static String preparePlaceHolders(int length) { return String.join(",", Collections.nCopies(length, "?")); } public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException { for (int i = 0; i < values.length; i++) { preparedStatement.setObject(i + 1, values[i]); } } 

以下是您可以使用它的方法:

 private static final String SQL_FIND = "SELECT id, name, value FROM entity WHERE id IN (%s)"; public List<Entity> find(Set<Long> ids) throws SQLException { List<Entity> entities = new ArrayList<Entity>(); String sql = String.format(SQL_FIND, preparePlaceHolders(ids.size())); try ( Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(sql); ) { setValues(statement, ids.toArray()); try (ResultSet resultSet = statement.executeQuery()) { while (resultSet.next()) { entities.add(map(resultSet)); } } } return entities; } private static Entity map(ResultSet resultSet) throws SQLException { Enitity entity = new Entity(); entity.setId(resultSet.getLong("id")); entity.setName(resultSet.getString("name")); entity.setValue(resultSet.getInt("value")); return entity; } 

请注意,某些数据库在IN子句中具有可允许的值数量限制。 例如,Oracle对1000个项目有这个限制。

由于没有人回答一个大的IN子句(超过100)的情况下,我会抛出我的解决scheme,这个问题很好地适用于JDBC。 简而言之,我用tmp表上的INNER JOINreplaceIN

我所做的是使我称之为批ID表,并根据RDBMS我可以做一个TMP表或内存表。

该表有两列。 一列有来自IN子句的ID,另一列有我在飞行中产生的批次ID。

 SELECT * FROM MYTABLE M INNER JOIN IDTABLE T ON T.MYCOL = M.MYCOL WHERE T.BATCH = ? 

在select之前,用给定的批次ID将您的ID推入表格。 那么你只需要用你的id表中的INNER JOINreplace你的原始查询IN子句WHERE batch_id等于你当前的批处理。 完成之后,为您批量删除条目。

这样做的标准方法是(如果您使用Spring JDBC)是使用org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate类。

使用此类,可以将List定义为SQL参数,并使用NamedParameterJdbcTemplate来replace命名参数。 例如:

 public List<MyObject> getDatabaseObjects(List<String> params) { NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource); String sql = "select * from my_table where my_col in (:params)"; List<MyObject> result = jdbcTemplate.query(sql, Collections.singletonMap("params", params), myRowMapper); return result; } 

我通过构buildSQLstring来解决这个问题? 因为我有价值观。

 SELECT * FROM MYTABLE WHERE MYCOL in (?,?,?,?) 

首先我search了一个我可以传入语句的数组types,但所有JDBC数组types都是供应商特定的。 所以我留在多个?

我从docs.spring得到了答案(19.7.3)

SQL标准允许根据包含variables列表的expression式来select行。 一个典型的例子是select * from T_ACTOR,其中id在(1,2,3)中。 这个variables列表并不直接支持JDBC标准的预处理语句; 你不能声明可变数目的占位符。 您需要准备好一定数量的占位符,然后在知道需要多less占位符时,需要dynamic生成SQLstring。 NamedParameterJdbcTemplate和JdbcTemplate中提供的named参数支持采用后一种方法。 将这些值作为基本对象的java.util.List传递。 该列表将用于插入所需的占位符,并在语句执行过程中传递值。

希望这可以帮助你。

AFAIK,在JDBC中没有处理集合作为参数的标准支持。 如果你能通过一个列表,这将是很好的,这将是扩大。

Spring的JDBC访问支持作为parameter passing集合。 你可以看看这是如何安全地进行编码的灵感。

请参阅将集合自动扩展为JDBC参数

(本文首先讨论Hibernate,然后继续讨论JDBC。)

看到我的审判和成功,据说名单大小有潜在的限制。 List l = Arrays.asList(new Integer [] {12496,12497,12498,12499}); Map param = Collections.singletonMap(“goodsid”,l);

  NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(getJdbcTemplate().getDataSource()); String sql = "SELECT bg.goodsid FROM beiker_goods bg WHERE bg.goodsid in(:goodsid)"; List<Long> list = namedParameterJdbcTemplate.queryForList(sql, param2, Long.class); 

我们可以使用不同的替代方法。

  1. 执行单个查询 – 速度慢,不推荐
  2. 使用存储过程 – 数据库特定
  3. dynamic创buildPreparedStatement查询 – 性能良好但cachingfunction松散,需要重新编译
  4. 在PreparedStatement Query中使用NULL – 我认为这是一个优化性能的好方法。

在这里查看更多细节。

sormula使这很简单(见例4 ):

 ArrayList<Integer> partNumbers = new ArrayList<Integer>(); partNumbers.add(999); partNumbers.add(777); partNumbers.add(1234); // set up Database database = new Database(getConnection()); Table<Inventory> inventoryTable = database.getTable(Inventory.class); // select operation for list "...WHERE PARTNUMBER IN (?, ?, ?)..." for (Inventory inventory: inventoryTable. selectAllWhere("partNumberIn", partNumbers)) { System.out.println(inventory.getPartNumber()); } 

我能想到的一个方法是使用java.sql.PreparedStatement和一些陪审团索具

PreparedStatement preparedStmt = conn.prepareStatement(“SELECT * FROM MYTABLE WHERE MYCOL in(?)”);

… 接着 …

preparedStmt.setString(1,[你的string参数]);

http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html