使用准备好的语句查询列表 (JDBC)

Posted

技术标签:

【中文标题】使用准备好的语句查询列表 (JDBC)【英文标题】:Querying list with prepared statement (JDBC) 【发布时间】:2012-10-28 21:16:14 【问题描述】:

我现在有一个方法,如下所示:

public void foo(Date date) 
    PreparedStatement stmt; 
    ResultSet rs;
    java.sql.Date sDate = new java.sql.Date(date.getTime());

    try 
        String sql = "select * from some_table p where p.start_date <=? and ?<= p.end_date";
        stmt = getConnection().preparedStatement(sql);
        stmt.setDate(1, sDate);
        stmt.setDate(2, sDate);
        rs = stmt.executeQuery();
        //... 
     finally 
        if (rs != null)  rs.close(); 
        if (stmt != null)  stmt.close(); 
    

现在我不想传递一个 Date 对象,而是传递日期列表 (List&lt;Date&gt; dates)。我想我在技术上可以多次调用 foo,同时遍历列表,但是有没有一种方法可以实现这一点而不必多次调用 foo?

【问题讨论】:

我们可以在多个日期申请 你必须多次调用它 那么迭代是我唯一的选择吗? 我认为您应该修改查询条件以检查范围,而不是尝试传入日期列表。您并没有告诉我们您最终想要达到的目标。 【参考方案1】:

考虑将 Date 对象的 ArrayList 传递给您的 foo(...) 方法并使用它,而不是传递单个 Date 对象。

您有多种选择。

选项 1:通过更改参数多次执行 PreparedStatement

public void foo(ArrayList<Date> dateList) 
    if(dateList == null)
        return;

    PreparedStatement stmt = null;
    ResultSet rs = null;    
    java.sql.Date sDate = null;
    try
        stmt = getConnection().preparedStatement("select * from some_table p where p.start_date <=? and ?<= p.end_date");

        for(Date date: dateList)
            try
                sDate = new java.sql.Date(date.getTime());
                stmt.clearParameters(); //Clear current parameter values
                stmt.setDate(1, sDate);
                stmt.setDate(2, sDate);
                rs = stmt.executeQuery();

                //perform your operations
            finally
                sDate = null;
                //mange your resultset closing
            
        
    finally
        //your resource management code
      

选项 2:创建一个 SQL 查询,考虑到您在列表中的日期数,执行此语句,然后使用结果集。

public void foo(ArrayList<Date> dateList) 
    if(dateList == null)
        return;

    PreparedStatement stmt = null;
    ResultSet rs = null;    
    java.sql.Date sDate = null;
    StringBuilder builder = new StringBuilder();

    try
        //1. Create your dynamic statement
        builder.append("SELECT * FROM some_table p WHERE \n");
        for(int index = 0; index < dateList.length; index++)
            if(index > 0)
                builder.append(" OR \n");
            builder.append("(p.start_date <=? and ?<= p.end_date)");
        

        stmt = getConnection().preparedStatement(builder.toString());

        //2. Set the parameters
        int index = 1;
        for(Date date: dateList)
            try
                sDate = new java.sql.Date(date.getTime());
                stmt.setDate(index, sDate);
                stmt.setDate(index+1, sDate);
                index += 2;
            finally
                sDate = null;
                //mange your resultset closing
            
        

        //3. execute your query
        rs = stmt.executeQuery();

        //4. perform your operations
    finally
        builder = null;
        //your resource management code
    


【讨论】:

@alexispigeon - 哎呀,没有看到这种混淆。感谢您的编辑:)【参考方案2】:

这是一种仅使用一次数据库调用的解决方案。这不会检查 null 或空dateList,相反它假定至少有一个元素。

public void foo(List<Date> dateList) 
    PreparedStatement stmt; 
    ResultSet rs;

    try 
        // Step 1 : build the query string, based on the number of elements in the list
        StringBuilder sql = new StringBuilder("select * from some_table p where (p.start_date <=? and ?<= p.end_date)");
        if (dateList.size() > 1) 
            for (int i = 1; i < dateList.size(); i++) 
                sql.append(" or (p.start_date <=? and ?<= p.end_date)");
            
        

        stmt = getConnection().preparedStatement(sql.toString());

        // Step 2 : pass the actual list of dates to the query
        for (int i = 0; i < dateList.size(); i++) 
            java.sql.Date date = new java.sql.Date(dateList.get(i).getTime());
            stmt.setDate((i * 2) + 1, date);
            stmt.setDate((i * 2) + 2, date);
        

        rs = stmt.executeQuery();
        //... 
     finally 
        if (rs != null)  rs.close(); 
        if (stmt != null)  stmt.close(); 
    

【讨论】:

以上是关于使用准备好的语句查询列表 (JDBC)的主要内容,如果未能解决你的问题,请参考以下文章

使用 neo4j jdbc 驱动程序和 neo4j 4 准备好的语句中的密码查询参数的语法是啥?

如何将此代码转换为准备好的语句或 jdbc 中的语句? [关闭]

准备好的语句中的占位符

在哪里使用 JDBC 创建准备好的语句?

如何使用 jdbc 准备好的语句传递可变数量的参数?

限制准备好的语句一次执行一个查询