Como usar um procedimento armazenado com parâmetros de saída

Baixar Driver JDBC

Um procedimento armazenado do SQL Server que pode ser chamado é aquele que retorna um ou mais parâmetros OUT, que são parâmetros usados pelo procedimento armazenado para retornar os dados ao aplicativo de chamada. O Microsoft JDBC Driver para SQL Server fornece a classe SQLServerCallableStatement que pode ser usada para chamar esse tipo de procedimento armazenado e processar os dados que ele retorna.

Ao chamar esse tipo de procedimento armazenado usando o driver JDBC, você precisa usar a sequência de escape call do SQL junto com o método prepareCall da classe SQLServerConnection. A sintaxe da sequência de escape call com parâmetros OUT é a seguinte:

{call procedure-name[([parameter][,[parameter]]...)]}

Observação

Para obter mais informações sobre as sequências de escape SQL, confira Como usar sequências de escape do SQL.

Ao construir a sequência de escape call, especifique os parâmetros OUT usando o caractere ? (ponto de interrogação). Esse caractere age como um espaço reservado para os valores de parâmetros que retornarão do procedimento armazenado. Para especificar um valor para um parâmetro OUT, especifique o tipo de dados de cada parâmetro usando o método registerOutParameter da classe SQLServerCallableStatement antes de executar o procedimento armazenado.

O valor especificado para o parâmetro OUT no método registerOutParameter precisa ser um dos tipos de dados do JDBC contidos em java.sql.Types que, por sua vez, é mapeado para um dos tipos de dados nativos do SQL Server. Para obter mais informações sobre os tipos de dados JDBC e SQL Server, confira Noções básicas sobre os tipos de dados do JDBC Driver.

Ao passar para o método registerOutParameter um valor para um parâmetro OUT, especifique não só o tipo de dados a ser usado para o parâmetro, mas também o posicionamento ordinal do parâmetro ou o nome do parâmetro no procedimento armazenado. Por exemplo, se o procedimento armazenado contiver um único parâmetro OUT, seu valor ordinal será 1; se o procedimento armazenado contiver dois parâmetros, o primeiro valor ordinal será 1 e o segundo valor ordinal será 2.

Observação

O driver JDBC não dá suporte ao uso dos tipos de dados CURSOR, SQLVARIANT, TABLE e TIMESTAMP do SQL Server como parâmetros OUT.

Como exemplo, crie o seguinte procedimento armazenado no banco de dados de exemplo AdventureWorks2022:

CREATE PROCEDURE GetImmediateManager  
   @employeeID INT,  
   @managerID INT OUTPUT  
AS  
BEGIN  
   SELECT @managerID = ManagerID
   FROM HumanResources.Employee
   WHERE EmployeeID = @employeeID  
END

Esse procedimento armazenado retorna um único parâmetro OUT (managerID), que é um inteiro, com base no parâmetro IN especificado (employeeID), que também é um inteiro. O valor retornado no parâmetro OUT é o ManagerID baseado no EmployeeID contido na tabela HumanResources.Employee.

No seguinte exemplo, uma conexão aberta com o banco de dados de exemplo AdventureWorks2022 é passada para a função, e o método execute é usado para chamar o procedimento armazenado GetImmediateManager:

public static void executeStoredProcedure(Connection con) throws SQLException {  
    try(CallableStatement cstmt = con.prepareCall("{call dbo.GetImmediateManager(?, ?)}");) {  
        cstmt.setInt(1, 5);  
        cstmt.registerOutParameter(2, java.sql.Types.INTEGER);  
        cstmt.execute();  
        System.out.println("MANAGER ID: " + cstmt.getInt(2));  
    }  
}

Esse exemplo usa as posições ordinais para identificar os parâmetros. Como alternativa, você pode identificar um parâmetro usando seu nome em vez da sua posição ordinal. O exemplo de código a seguir modifica o exemplo anterior para demonstrar como usar os parâmetros nomeados em um aplicativo Java. Observe que os nomes de parâmetro correspondem aos nomes de parâmetro na definição do procedimento armazenado:

public static void executeStoredProcedure(Connection con) throws SQLException {  
    try(CallableStatement cstmt = con.prepareCall("{call dbo.GetImmediateManager(?, ?)}"); ) {  
        cstmt.setInt("employeeID", 5);  
        cstmt.registerOutParameter("managerID", java.sql.Types.INTEGER);  
        cstmt.execute();  
        System.out.println("MANAGER ID: " + cstmt.getInt("managerID"));  
    }  
}

Para drivers versão 12.6 e superiores, foi introduzida uma nova propriedade de conexão useFlexibleCallableStatements. Quando definida como true, esta propriedade mantém o comportamento antigo do driver, permitindo que os usuários usem uma combinação de posições ordinais e nomes de parâmetros ao identificar parâmetros. Quando definido como false, o usuário deve usar um ou outro, mas não pode usar ambos.

Além disso, useFlexibleCallableStatements mantém o comportamento existente em relação aos parâmetros flexíveis da instrução de solicitação que podem ser definidos quando a propriedade é definida comotrue. Entretanto, quando definida como false, a ordem deve corresponder à definição do procedimento armazenado. Ambos os recursos para useFlexibleCallableStatements=true podem ser vistos no exemplo a seguir:

public static void executeStoredProcedure(Connection con) throws SQLException {  
    try(CallableStatement cstmt = con.prepareCall("{call dbo.GetImmediateManager(?, ?)}"); ) {
        cstmt.registerOutParameter("managerID", java.sql.Types.INTEGER);
        cstmt.setInt(1, 5);  
        cstmt.execute();  
        System.out.println("MANAGER ID: " + cstmt.getInt("managerID"));  
    }  
}

Observação

Esses exemplos usam o método de execução da classe SQLServerCallableStatement para executar o procedimento armazenado. Ele é usado porque o procedimento armazenado também não retornou um conjunto de resultados. Se ele tivesse retornado, o método executeQuery teria sido usado.

Os procedimentos armazenados podem retornar contagens de atualização e vários conjuntos de resultados. O Microsoft JDBC Driver para SQL Server segue a especificação do JDBC 3.0, a qual declara que vários conjuntos de resultados e contagens de atualização devem ser recuperados antes que os parâmetros OUT sejam recuperados. Ou seja, o aplicativo deve recuperar todos os objetos ResultSet e as contagens de atualização antes de recuperar os parâmetros OUT usando os métodos CallableStatement.getter. Caso contrário, os objetos ResultSet e as contagens de atualizações que ainda não foram recuperados serão perdidos quando os parâmetros OUT forem recuperados. Para obter mais informações sobre contagens de atualizações e vários conjuntos de resultados, confira Como usar um procedimento armazenado com uma contagem de atualização e Como usar vários conjuntos de resultados.

Confira também

Como usar instruções com procedimentos armazenados