Получение исключений из PreparedStatement - PullRequest
0 голосов
/ 18 марта 2019

Описание проблемы

У меня есть небольшой сценарий SQL, состоящий из нескольких оценок:

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

Я хочу выполнить его на сервере Microsoft SQL Server, используя простой JDBC. Поскольку таблица 'test' не существует, я ожидаю исключения. Звучит просто, но это не так. Если я выполню

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

     hasMoreResultSets = stmt.execute(SQL);

Я не получаю исключения. Зачем? Так как первый SELECT не вызывает исключение, исключение становится троном, только если я запрашиваю ResultSet второго оператора, вызывая getMoreResults ():

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();

    }

}

Это успешно компилируется, но это НЕ работает. Не исключение не выбрасывается. Даже попытка получить исключение, просматривая все наборы результатов, не работает.

Итак, я задаю несколько вопросов:

  • Кто-нибудь знает, как получить Исключение?
  • Это ошибка в драйвере JDBC от Microsoft?
  • Есть ли какая-либо документация о различиях между 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());

    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...