简体   繁体   English

参数无法在Java中运行的SQLite查询

[英]SQLite Query With Parameters Not Working in Java

I have a program that selects from a database given a table and column string. 我有一个程序,从给定表和列字符串的数据库中选择。

public void selectAllFrom(String table, String column){
        String sql = "SELECT ? FROM ?";

        try (Connection conn = this.connect();
             PreparedStatement pstmt  = conn.prepareStatement(sql)){
            pstmt.setString(1, column);
            pstmt.setString(2, table);

            ResultSet rs = pstmt.executeQuery();

            while (rs.next()){
                System.out.println(rs.getString(column));
            }

        } catch (SQLException e){
            System.out.println(" select didn't work");
            System.out.println(e.getMessage());
        }
    }

For some reason it is not working and it is going right to catch 由于某种原因,它无法正常工作,并且可以正确捕获

Here is the connect() function as well: 这也是connect()函数:

private Connection connect(){
    Connection conn = null;
    // SQLite connection string
    String url = "jdbc:sqlite:C:/sqlite/db/chinook.db";

    try{
    // creates connection to the database
    conn = DriverManager.getConnection(url);
    System.out.println("Connection to SQLite has been established");
    } catch (SQLException e){
        System.out.println(e.getMessage());
        System.out.println("Connection didn't work");
    } 

    return conn;
}

I know the problem is not with the database because I'm able to run other select queries without parameters. 我知道问题不在于数据库,因为我可以运行其他不带参数的选择查询。 It is the parameters that are giving me the problem. 是参数给了我这个问题。 Can anyone tell what the problem is? 谁能说出问题所在?

A table or column name can't be used as a parameter to PreparedStatement. 表或列名不能用作PreparedStatement的参数。 It must be hard coded. 它必须是硬编码的。

String sql = "SELECT " + column + " FROM " + table;

You should reconsider the design so as to make these two constant and parameterize the column values. 您应该重新考虑设计,以使这两个常数保持不变并参数化列值。

? is a place holder to indicate a bind variable. 是表示绑定变量的占位符。 When a SQL statement is executed, database first checks syntax, and validates the objects being referenced, columns and access permission for specified objects (ie metadata about objects) and confirms that all are in place and valid. 当执行一条SQL语句时,数据库首先检查语法,并验证所引用的对象,指定对象的列和访问权限(即有关对象的元数据),并确认所有这些都就位并且有效。 This stage is called parsing. 这个阶段称为解析。

Post parsing, it substitutes bind variables to query and then proceeds for actual fetch of results. 解析后,它将绑定变量替换为查询,然后继续进行实际的结果获取。

Bind variables can be substituted in any place in query to replace an actual hard coded data/strings, but not the query constructs them selves. 可以在查询中的任何位置替换绑定变量,以替换实际的硬编码数据/字符串,但是查询无法自行构造它们。 It means 它的意思是

  • You can not use bind variables for keywords of sql query (ex: SELECT, UPDATE etc.) 您不能将绑定变量用于sql查询的关键字(例如:SELECT,UPDATE等)
  • You can not use bind variables for objects or their attributes (ie table names, column names, functions, procedures etc.) 您不能将绑定变量用于对象或其属性(即表名,列名,函数,过程等)。
  • You can use them only in place of a otherwise hard coded data. 您只能使用它们代替原本硬编码的数据。

ex: SELECT FIRST_NAME, LAST_NAME, 'N' IS_DELETED FROM USER_DATA WHERE COUNTRY ='CANADA' AND VERIFIED_USER='YES' In above sample query, 'N' , 'CANADA' and 'YES' are the only strings which can be replaced by a bind variable, not any other word. 例如: SELECT FIRST_NAME, LAST_NAME, 'N' IS_DELETED FROM USER_DATA WHERE COUNTRY ='CANADA' AND VERIFIED_USER='YES'在上面的示例查询中, 'N''CANADA''YES'是唯一可以替换为的字符串绑定变量,而不是其他任何单词。

Using bind variable is best practice of coding. 使用绑定变量是编码的最佳实践。 It improves query performance (when used with large no. of queries in tuned database products like Oracle or MSSQL) and also protects your code against sql injection attacks. 它提高了查询性能(当在经过调整的数据库产品(如Oracle或MSSQL)中使用大量查询时),还可以保护您的代码免受sql注入攻击。

Constructing query by concatenating strings (especially data part of query) is never recommended way. 从来不建议通过串联字符串(尤其是查询的数据部分)来构造查询。 You can still construct a query by concatenation for other parts like table name or column name as long as those strings are not directly taken from input. 您仍然可以通过串联构造其他查询,例如表名或列名,只要这些字符串不是直接从输入中获取的。

Below example is acceptable: 下面的例子是可以接受的:

query = "Select transaction_id, transaction_date from ";
if (isHistorical(reportType) 
   { query = query + "HISTORY_TRANSACTIONS" ;}
else
   {query = query + "PRESENT_TRANSACTIONS" ; }

recommended practice is to use 推荐的做法是使用

String query_present = "SELECT transaction_id, transaction_date from PRESENT_TRANSACTIONS";
String query_historical = "SELECT transaction_id, transaction_date from HISTORY_TRANSACTIONS";

if (isHisotrical(reportType))
 { 
    ps.executeQuery(query_historical);
 }else{
    ps.executeQuery(query_present);
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM