第二次使用准备好的语句无法到达临时表

时间:2018-12-13 10:45:13

标签: java sql-server prepared-statement sql-injection

我正在代码中使用临时表,以便在[SQL Server,Java中使用某些原因]。我正在使用Java中的Stament对象执行SQL查询。但是,最近我决定使用PreparedStatement以避免注入。

我的问题是,当使用PreparedStatement创建临时表时,无法再次使用相同的Prepared语句到达它。这是一个简单的例子:

sql = "select * into #someTable from (select someColumns from someOtherTable where smth = ? and smth2 = ?)"
PreparedStatement preparedStatement = conn.prepareStatement(sql);
for(int i=0; i<parameters.size(); i++){
   preparedStatement.setString(i+1, parameters.get(i).toString());
}

this.rs = preparedStatement.executeQuery();

直到这里,没关系。获得ResultSet并对其进行处理之后,或者未获得仅用于preparedStatement.execute()的resultSet都没有区别,我无法再次到达#someTable对象。

sql = "select count(*) from #someTable"
preparedStatement = conn.prepareStatement(sql);
this.rs = preparedStatement.executeQuery();

此处this.rs = preparedStatement.executeQuery();部分给出了'Invalid object name #someTable'。我仅使用一个Connection对象就可以完成上述所有操作,而无需关闭或重新打开它。我需要再次使用该临时表。有什么方法可以用Java中的PreparedStatement对象创建临时表并一次又一次地重用此临时表?问候

2 个答案:

答案 0 :(得分:0)

您在第一条语句中创建的临时表在该请求的范围\生存期内存在。调用另一个查询后,您将进入另一个范围,因此不再存在,因为它将被清除。

解决方案要么是在同一调用中发出2个请求(不是很好),要么创建了一个可以被第二个查询访问的全局临时表(仍然不是很好)。

更好的解决方案是创建一个存储过程,该过程执行您所需的所有工作,并在过程中封装临时表,进行查询和整理。

PS我看不到任何周围的代码,但是在用这种代码构建查询时要小心SQL注入。

相关信息: Scope of temporary tables in SQL Server

答案 1 :(得分:0)

参加聚会的时间很晚,但是面临相同的问题并发现上述答案有误:

阅读有关该问题的这篇文章:https://docs.microsoft.com/en-us/sql/connect/jdbc/using-usefmtonly?view=sql-server-2017

我发现使用PreparedStatement创建临时表是行不通的,但是如果我更改为使用Statement创建临时表,它将行得通(即使没有useFmtOnly)。 因此,首先从MS文章开始并以此为基础:

final String sql = "INSERT INTO #Bar VALUES (?)";
try (Connection c = DriverManager.getConnection(URL, USERNAME, PASSWORD)) {
    try (Statement s = c.createStatement()) {
        s.execute("CREATE TABLE #Bar(c1 int)");
    }
    try (PreparedStatement p1 = c.prepareStatement(sql); PreparedStatement p2 = c.prepareStatement(sql)) {
        ((SQLServerPreparedStatement) p1).setUseFmtOnly(true);
        ParameterMetaData pmd1 = p1.getParameterMetaData();
        System.out.println(pmd1.getParameterTypeName(1)); // prints int
        ParameterMetaData pmd2 = p2.getParameterMetaData(); // throws exception, Invalid object name '#Bar'
    }
}