Пакетная обработка в JDBC
1. Вступление
Java Database Connectivity (JDBC) - это Java API, используемый для взаимодействия с базами данных. Пакетная обработка группирует несколько запросов в один блок и передает их в одной сетевой поездке в базу данных.
В этой статье мы узнаем, как JDBC можно использовать для пакетной обработки SQL-запросов.
Чтобы узнать больше о JDBC, вы можете ознакомиться с нашей вводной статьейhere.
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')");
Типичная проблема в вышеупомянутом подходе возникает, когда первый оператор завершается успешно, а второй - не выполняется. In this situation there is no rollback of the data inserted by the first statement, leading to data inconsistency.с
Мы можем добиться согласованности данных, распределив транзакцию между несколькими вставками / обновлениями и затем зафиксировав транзакцию в конце или выполнив откат в случае исключений, но в этом случае мы все равно повторно обращаемся к базе данных для каждого оператора.
3. Как сделать пакетную обработку
JDBC предоставляет два классаStatement иPreparedStatement для выполнения запросов к базе данных. Оба класса имеют собственную реализацию методовaddBatch() иexecuteBatch(), которые предоставляют нам функциональность пакетной обработки.
3.1. Пакетная обработка с использованиемStatement
С JDBC самый простой способ выполнять запросы к базе данных - через объектStatement.
Во-первых, используяaddBatch(), мы можем добавить все SQL-запросы в пакет, а затем выполнить эти SQL-запросы с помощьюexecuteBatch().
Тип возвратаexecuteBatch() - это массивint, указывающий, сколько записей было затронуто выполнением каждого оператора SQL.
Давайте посмотрим на пример создания и выполнения пакета с помощью Statement:
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.
Как всегда, код, относящийся к этой статье, можно найтиover on Github.