从PreparedStatement获取异常

时间:2019-03-18 17:09:46

标签: sql-server tsql jdbc

问题描述

我有一个包含多个语句的小型SQL脚本:

  private static final String SQL = "SELECT 1; INSERT INTO test (test) VALUES (23);";

我想使用纯JDBC针对Microsoft SQL Server执行它。由于表“ test”不存在,因此我希望引发异常。听起来很简单,但事实并非如此。如果我执行

try (Statement stmt = con.createStatement();) {                

     hasMoreResultSets = stmt.execute(SQL);

我没有例外。为什么?由于第一个SELECT不会触发异常,因此如果我通过调用getMoreResults()来请求第二条语句的ResultSet,则该异常仅是thron。

while (hasMoreResultSets) {

   System.out.println("Resultset found");
   ResultSet rs = stmt.getResultSet();
   rs.next();
   rs.close();

   hasMoreResultSets = stmt.getMoreResults();

} 

太好了!这很麻烦但是有效。但是现在我必须使用PreparedStatement(这是一个使用PreparedStatement的开放源代码项目中的库,因此我无法通过切换到纯语句来轻松解决此问题。)切换到PreparedStatement很容易:

boolean hasMoreResultSets;
try (PreparedStatement stmt = con.prepareStatement(SQL);) {

    hasMoreResultSets = stmt.execute();

    while (hasMoreResultSets) {

        ResultSet rs = stmt.getResultSet();
        rs.next();
        rs.close();

        hasMoreResultSets = stmt.getMoreResults();

    }

}

这可以成功编译,但是不起作用。没有异常被抛出。甚至试图通过查看所有结果集来获取异常也不起作用。

所以我提出了多个问题:

  • 有人知道如何获取异常吗?
  • 这是Microsoft JDBC驱动程序中的错误吗?
  • 是否有任何有关Statement与PreparedStatement差异的文档?
  • 尤其:根据JDBC规范,使用准备好的语句来执行多个语句是否合法?

完整的测试用例

如果您想解决这个问题,我已经提供了完整的测试用例。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>de.thoughtgang.otto</groupId>
    <artifactId>sql-server-test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.surefire.plugin.version>2.22.1</maven.surefire.plugin.version>
        <junit.jupiter.version>5.3.1</junit.jupiter.version>
        <junit.platform.version>1.4.0</junit.platform.version>  
    </properties>

    <dependencies>

                <dependency>
                        <groupId>org.junit.jupiter</groupId>
                        <artifactId>junit-jupiter-api</artifactId>
                        <version>${junit.jupiter.version}</version>
                        <scope>test</scope>
                </dependency>
                <dependency>
                        <groupId>org.junit.jupiter</groupId>
                        <artifactId>junit-jupiter-engine</artifactId>
                        <version>${junit.jupiter.version}</version>
                        <scope>test</scope>
                </dependency>
                <dependency>
                        <groupId>com.microsoft.sqlserver</groupId>
                        <artifactId>mssql-jdbc</artifactId>
                        <version>7.2.1.jre8</version>
                        <scope>test</scope>
                    </dependency>
    </dependencies>

    <build>
        <plugins>
                <plugin>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <version>${maven.surefire.plugin.version}</version>
                </plugin>
        </plugins>
    </build>


</project>

SQLServerExceptionTest.java

import com.microsoft.sqlserver.jdbc.SQLServerException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.jupiter.api.AfterAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;


@TestInstance(Lifecycle.PER_CLASS)
public class SQLServerExceptionTest {

    private static final String URL ="jdbc:sqlserver://localhost;databaseName=master";
    private static final String USERNAME = "sa";
    private static final String PASSWORD = "MSSQLServer2017";
    private static final String SQL = "SELECT 1; INSERT INTO test (test) VALUES (23);";

    private Connection con;

    @BeforeAll
    public void beforeAll() throws ClassNotFoundException, SQLException {

        Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        con = DriverManager.getConnection(URL, USERNAME, PASSWORD);

    }

    @AfterAll
    public void afterAll() throws SQLException {

        if (con != null && ! con.isClosed()) {

            con.close();

        }

    }


    /**
     * This unit test will execute the SQL string consisting of multiple statments but
     * using a Prepared Statement. It fails to detect the error that occurs because there
     * is not table 'test'.
     */
    @Test
    public void testPreparedStatement()  {

        SQLServerException sqlex = assertThrows(SQLServerException.class, () -> {
            boolean hasMoreResultSets;
            try (PreparedStatement stmt = con.prepareStatement(SQL);) {

                hasMoreResultSets = stmt.execute();
                System.out.println(hasMoreResultSets);

                while (hasMoreResultSets) {

                    System.out.println("Resultset found");
                    ResultSet rs = stmt.getResultSet();
                    rs.next();
                    rs.close();

                    hasMoreResultSets = stmt.getMoreResults();

                }

                System.out.println(stmt.getMoreResults());

            }

        });

         assertEquals("Invalid object name 'test'.", sqlex.getMessage());

    }

    /**
     * This unit test will execute the SQL string consisting of multiple statments and
     * successfully detect that an error has occured.
     */
    @Test
    public void testStatement() {

        SQLServerException sqlex = assertThrows(SQLServerException.class, () -> {
            boolean hasMoreResultSets;
            try (Statement stmt = con.createStatement();) {                

                hasMoreResultSets = stmt.execute(SQL);

                System.out.println(hasMoreResultSets);

               /* while (hasMoreResultSets) {

                    System.out.println("Resultset found");
                    ResultSet rs = stmt.getResultSet();
                    rs.next();
                    rs.close();

                    hasMoreResultSets = stmt.getMoreResults();

                } 

                System.out.println(stmt.getMoreResults()); */
            }
        });

        assertEquals("Invalid object name 'test'.", sqlex.getMessage());

    }

}

0 个答案:

没有答案