Java SQL Server: вызов хранимых процедур

В этом руководстве вы узнаете, как вызвать хранимую процедуру в SQL Server из программы Java с использованием JDBC.

Это руководство начинается с того места, где закончилось руководство «Выполнение транзакции в Java».

Как вызвать хранимую процедуру из Java с помощью JDBC

Ниже приведены шаги для вызова хранимой процедуры в SQL Server из Java с использованием JDBC:

  • Сначала подключитесь к базе данных SQL Server с помощью JDBC.
  • Во-вторых, создайте CallableStatement для выполнения хранимой процедуры.
  • В-третьих, свяжите входные параметры оператора, вызывающего хранимую процедуру.
  • В-четвертых, выполните CallableStatement, который вызывает хранимую процедуру.
  • В-пятых, обработайте набор результатов, возвращаемый хранимой процедурой.
  • Наконец, закройте ресурсы, включая ResultSet, CallableStatement и Connection, чтобы освободить ресурсы. Если вы используете оператор try-with-resources, вам не нужно выполнять этот шаг вручную.

Создание новой хранимой процедуры

Шаг 1. Запустите Microsoft SQL Server Management Studio(SSMS) и подключитесь к SQL Server.

Шаг 2.Создайте новую хранимую процедуру, выполнив следующий оператор:

CREATE PROCEDURE GetBooksByPublishedDate
    @StartDate DATE,
    @EndDate DATE
AS
BEGIN
    -- Check for valid date range
    IF @StartDate > @EndDate
    BEGIN
        PRINT 'Error: Start date must be less than or equal to end date.'
        RETURN
    END
    -- Retrieve books within the date range
    SELECT BookID, Title, Publisher, ISBN, PublishedDate
    FROM Books
    WHERE PublishedDate BETWEEN @StartDate AND @EndDate
    ORDER BY PublishedDate;
END

Хранимая процедура GetBooksByPublishedDate возвращает список книг с датами публикации между начальной и конечной датами.

Вызов хранимой процедуры

Шаг 1. Определите класс Book, который представляет каждую строку в таблице Books:

import java.time.LocalDate;
public class Book {
    private int bookId;
    private String title;
    private String publisher;
    private String isbn;
    private LocalDate publishedDate;
    public Book(int bookId, String title, String publisher, String isbn, LocalDate publishedDate) {
        this.bookId = bookId;
        this.title = title;
        this.publisher = publisher;
        this.isbn = isbn;
        this.publishedDate = publishedDate;
    }
    public Book(String title, String publisher, String isbn, LocalDate publishedDate) {
        this(0, title, publisher, isbn, publishedDate);
    }
    public int getBookId() {
        return bookId;
    }
    public void setBookId(int bookId) {
        this.bookId = bookId;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getPublisher() {
        return publisher;
    }
    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }
    public String getIsbn() {
        return isbn;
    }
    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }
    public LocalDate getPublishedDate() {
        return publishedDate;
    }
    public void setPublishedDate(LocalDate publishedDate) {
        this.publishedDate = publishedDate;
    }
}

Шаг 2. Определите класс BookDB для взаимодействия с базой данных BookStore:

import java.sql.Date;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.time.LocalDate;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
public class BookDB {
    private final Connection connection;
    public BookDB(Connection connection) {
        this.connection = connection;
    }
    private Book createBookFrom(ResultSet rs) throws SQLException {
        return new Book(
                rs.getInt("BookID"),
                rs.getString("Title"),
                rs.getString("Publisher"),
                rs.getString("ISBN"),
                rs.getDate("PublishedDate").toLocalDate()
        );
    }
    public List findByPublishedDate(LocalDate fromDate, LocalDate toDate) throws DBException {
        var books = new ArrayList();
        String sql = "{CALL GetBooksByPublishedDate(?, ?)}";
        try(var stmt = connection.prepareCall(sql)) {
            stmt.setDate(1, Date.valueOf(fromDate));
            stmt.setDate(2, Date.valueOf(toDate));
            try(var rs = stmt.executeQuery()) {
                while(rs.next()) {
                    books.add(createBookFrom(rs));
                }
                return books;
            }
        } catch(SQLException e) {
            throw new DBException(e.getMessage());
        }
    }
}

Как это работает.

Сначала определите частное поле соединения:

private final Connection connection;

Во-вторых, инициализируйте объект соединения в конструкторе:

public BookDB(Connection connection) {
  this.connection = connection;
}

В-третьих, определите метод createBookFrom() для создания нового объекта Book из объекта ResultSet:

private Book createBookFrom(ResultSet rs) throws SQLException {
    return new Book(
            rs.getInt("BookID"),
            rs.getString("Title"),
            rs.getString("Publisher"),
            rs.getString("ISBN"),
            rs.getDate("PublishedDate").toLocalDate()
    );
}

В-четвертых, определите метод findByPublishedDate, который возвращает список объектов Book с датой публикации между fromDate и toDate:

public List findByPublishedDate(LocalDate fromDate, LocalDate toDate) throws DBException {

В-пятых, инициализируем объект списка книг:

var books = new ArrayList();

В-шестых, создайте оператор T-SQL, который вызывает хранимую процедуру:

String sql = "{CALL GetBooksByPublishedDate(?, ?)}";

Вопросительные знаки(?) являются заполнителями для параметров хранимой процедуры GetBooksByPublishedDate. При выполнении хранимой процедуры необходимо задать фактические значения этих параметров.

В-седьмых, создайте объект CallableStatemen:

try(var stmt = connection.prepareCall(sql)) {

В-восьмых, привяжите даты к параметрам запроса:

stmt.setDate(1, Date.valueOf(fromDate));
stmt.setDate(2, Date.valueOf(toDate));

Девятое, выполните вызов хранимой процедуры:

try(var rs = stmt.executeQuery()) {

В-десятых, выполните итерацию по строкам в результирующем наборе, преобразуйте каждую строку в объект Book и добавьте его в список книг:

while(rs.next()) {
  books.add(createBookFrom(rs));
}

Одиннадцатое, верните список книг:

return books;

Наконец, выдайте исключение DBException, если во время вызова возникнет какая-либо ошибка:

} catch(SQLException e) {
  throw new DBException(e.getMessage());
}

Шаг 3. Измените метод main() класса Main, чтобы использовать метод findByPublishedDate класса BookDB:

import java.sql.SQLException;
import java.time.LocalDate;
public class Main {
    public static void main(String[] args) {
        try(var connection = SQLServerConnection.connect()) {
            //
            var bookDB = new BookDB(connection);
            var fromDate = LocalDate.of(2021,1,1);
            var toDate = LocalDate.of(2022,12,31);
            var books = bookDB.findByPublishedDate(fromDate, toDate );
            for(var book: books) {
                System.out.println(book.getTitle()  + '\t' + book.getPublishedDate());
            }
        } catch(SQLException | DBException e) {
            System.err.println(e.getMessage());
        }
    }
}

Как это работает.

Сначала подключитесь к SQL Server:

try(var connection = SQLServerConnection.connect()) {

Во-вторых, создайте объект BookDB:

var bookDB = new BookDB(connection);

В-третьих, инициализируйте переменные, хранящие даты для передачи в метод findByPublishedDate:

var fromDate = LocalDate.of(2021, 1, 1);
var toDate = LocalDate.of(2022, 12, 31);

В-четвертых, выполните метод findByPublishedDate объекта bookDB для вызова хранимой процедуры:

var books = bookDB.findByPublishedDate(fromDate, toDate );

В-пятых, пройдитесь по списку книг и отобразите название книги и дату публикации:

for(var book: books) {
  System.out.println(book.getTitle() + '\t' + book.getPublishedDate());
}

Наконец, отобразите сообщение об ошибке:

} catch(SQLException | DBException e) {
  System.err.println(e.getMessage());
}

Шаг 4. Запустите программу.

Будет выведен следующий результат:

Inside SQL Server 2021-07-20
SQL Server Performance Tuning 2022-04-15
SQL Server Internals: A Deep Dive 2022-12-15

Загрузите исходный код проекта

Загрузите исходный код проекта

Краткое содержание

  • Используйте объект CallableStatement для вызова хранимой процедуры.
Мирослав С.

Автор статей, ИБ-специалист