Перейти к основному содержимому

Пакетная обработка в JDBC

· 4 мин. чтения

1. Введение

Java Database Connectivity (JDBC) — это Java API, используемый для взаимодействия с базами данных. Пакетная обработка группирует несколько запросов в один блок и передает его в базе данных за одно сетевое обращение.

В этой статье мы узнаем, как можно использовать JDBC для пакетной обработки запросов SQL.

Чтобы узнать больше о JDBC, вы можете прочитать нашу вводную статью здесь .

2. Почему пакетная обработка?

Производительность и согласованность данных являются основными мотивами для пакетной обработки.

2.1. Улучшенная производительность

В некоторых случаях использования требуется вставить большой объем данных в таблицу базы данных. При использовании JDBC одним из способов добиться этого без пакетной обработки является последовательное выполнение нескольких запросов.

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

statement.execute("INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) "
+ "VALUES ('1','EmployeeName1','Designation1')");
statement.execute("INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) "
+ "VALUES ('2','EmployeeName2','Designation2')");

Эти последовательные вызовы увеличат количество сетевых обращений к базе данных, что приведет к снижению производительности.

При использовании пакетной обработки эти запросы можно отправлять в базу данных за один вызов, что повышает производительность.

2.2. Согласованность данных

В определенных обстоятельствах данные необходимо помещать в несколько таблиц. Это приводит к взаимосвязанной транзакции, в которой важна последовательность отправляемых запросов.

Любые ошибки, возникающие во время выполнения, должны приводить к откату данных, переданных предыдущими запросами, если таковые имеются.

Давайте посмотрим на пример добавления данных в несколько таблиц:

statement.execute("INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) "
+ "VALUES ('1','EmployeeName1','Designation1')");
statement.execute("INSERT INTO EMP_ADDRESS(ID, EMP_ID, ADDRESS) "
+ "VALUES ('10','1','Address')");

Типичная проблема в описанном выше подходе возникает, когда первая инструкция выполняется успешно, а вторая не выполняется. В этой ситуации нет отката данных, вставленных первым оператором, что приводит к несогласованности данных.

Мы можем добиться согласованности данных, разделив транзакцию на несколько вставок/обновлений, а затем зафиксировав транзакцию в конце или выполнив откат в случае исключений, но в этом случае мы по-прежнему повторно обращаемся к базе данных для каждого оператора.

3. Как сделать пакетную обработку

JDBC предоставляет два класса, Statement и PreparedStatement , для выполнения запросов к базе данных. Оба класса имеют собственную реализацию методов addBatch() и executeBatch() , которые предоставляют нам функциональность пакетной обработки.

3.1. Пакетная обработка с использованием инструкции

В JDBC самый простой способ выполнения запросов к базе данных — через объект Statement .

Во- первых, с помощью addBatch() мы можем добавить все SQL-запросы в пакет, а затем выполнить эти SQL-запросы с помощью executeBatch() .

Тип возвращаемого значения executeBatch() представляет собой массив int , указывающий, сколько записей было затронуто выполнением каждого оператора SQL.

Давайте посмотрим на пример создания и выполнения пакета с использованием оператора:

Statement statement = connection.createStatement();
statement.addBatch("INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) "
+ "VALUES ('1','EmployeeName','Designation')");
statement.addBatch("INSERT INTO EMP_ADDRESS(ID, EMP_ID, ADDRESS) "
+ "VALUES ('10','1','Address')");
statement.executeBatch();

В приведенном выше примере мы пытаемся вставить записи в таблицы EMPLOYEE и EMP_ADDRESS с помощью Statement . Мы видим, как SQL-запросы добавляются в пакет для выполнения.

3.2. Пакетная обработка с использованием PreparedStatement

PreparedStatement — еще один класс, используемый для выполнения SQL-запросов . Это позволяет повторно использовать операторы SQL и требует от нас установки новых параметров для каждого обновления/вставки.

Давайте посмотрим на пример с использованием PreparedStatement. Во-первых, мы настраиваем оператор, используя SQL-запрос, закодированный как String:

String[] EMPLOYEES = new String[]{"Zuck","Mike","Larry","Musk","Steve"};
String[] DESIGNATIONS = new String[]{"CFO","CSO","CTO","CEO","CMO"};

String insertEmployeeSQL = "INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) "
+ "VALUES (?,?,?)";
PreparedStatement employeeStmt = connection.prepareStatement(insertEmployeeSQL);

Затем мы перебираем массив значений String и добавляем в пакет только что настроенный запрос.

После завершения цикла мы выполняем пакет:

for(int i = 0; i < EMPLOYEES.length; i++){
String employeeId = UUID.randomUUID().toString();
employeeStmt.setString(1,employeeId);
employeeStmt.setString(2,EMPLOYEES[i]);
employeeStmt.setString(3,DESIGNATIONS[i]);
employeeStmt.addBatch();
}
employeeStmt.executeBatch();

В приведенном выше примере мы вставляем записи в таблицу EMPLOYEE с помощью PreparedStatement. Мы можем видеть, как значения для вставки задаются в запросе, а затем добавляются в пакет для выполнения.

4. Вывод

В этой статье мы увидели, насколько важна пакетная обработка SQL-запросов при взаимодействии с базами данных с использованием JDBC.

Как всегда, код, относящийся к этой статье, можно найти на Github .