Эта статья является частью нашего академического курса под названием jOOQ — тип безопасного запроса в БД .
jOOQ — хороший выбор в приложении Java, где важны SQL и конкретная реляционная база данных. Это альтернатива, когда JPA / Hibernate слишком много абстрагирует, JDBC слишком мало. Он показывает, как современный предметно-ориентированный язык может значительно повысить производительность труда разработчиков, внедряя SQL в Java.
В этом курсе мы увидим, как мы можем эффективно запрашивать базы данных, используя jOOQ. Проверьте это здесь !
1. Введение
Хотя SQL является очень выразительным языком, большая часть вашего SQL, вероятно, CRUD (Create, Read, Update, Delete). Написание таких CRUD скучно и повторяется, поэтому ORM, такие как Hibernate, появились и добились успеха в увеличении производительности разработчиков. Но Hibernate делает много предположений (и ограничений) о вашей архитектуре, когда часто вы действительно просто хотите оперировать отдельными записями из таблиц.
Примеры, показанные в этом разделе, также доступны из пакета org.jooq.academy.section2 .
2. Простые активные записи операций
 jOOQ знает «активные записи» или UpdatableRecords , которые могут быть загружены «специальными» типами SELECT и которые затем отслеживают грязные флаги внутри.  Вот как вы можете обновить DATE_OF_BIRTH автора без написания слишком большого количества SQL: 
| 
 1 
2 
3 
 | 
AuthorRecord author = dsl.selectFrom(AUTHOR).where(AUTHOR.ID.eq(1)).fetchOne();author.setDateOfBirth(Date.valueOf("2000-01-01"));author.store(); | 
  Поскольку приведенный выше пример выбирает только одну таблицу с помощью selectFrom() , jOOQ знает, что результирующий тип записи будет AuthorRecord , то есть объектом, сгенерированным генератором кода.  AuthorRecord реализует AuthorRecord , который имеет множество полезных методов: 
-   store () чтобы 
INSERTилиUPDATEзапись - вставить (), чтобы вставить запись
 - обновить (), чтобы обновить запись
 -   удалить () чтобы 
DELETEзапись - refresh () для обновления записи из базы данных
 
В следующем разделе примеров приведен полный жизненный цикл создания, чтения, обновления и удаления такой записи:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
 | 
AuthorRecord author;// Create a new record and store it to the database. This will perform an INSERT statementauthor = dsl.newRecord(AUTHOR);author.setId(3);author.setFirstName("Alfred");author.setLastName("Hitchcock");author.store();// Read the record by refreshing it based on the primary key valueauthor = dsl.newRecord(AUTHOR);author.setId(3);author.refresh();// Update the record with a new valueauthor.setDateOfBirth(Date.valueOf("1899-08-13"));author.store();// Delete the record againauthor.delete(); | 
  UpdatableRecords в jOOQ отслеживает внутреннее «грязное» или «измененное» состояние каждого столбца, которое используется при вызове store() для того, чтобы вставлять / обновлять только те значения, которые были изменены в UpdatableRecord . 
3. Оптимистичная блокировка
При выполнении CRUD одновременный доступ к данным часто является проблемой, которая может быть решена двумя способами:
- Используя пессимистическую блокировку
 - Используя оптимистическую блокировку
 
Пессимистическая блокировка редко является хорошим выбором, поскольку взаимные блокировки могут легко возникнуть, когда два процесса блокируют несколько строк в таблице в различном порядке, ожидая завершения друг друга. Оптимистичная блокировка — гораздо лучшее решение. Одному процессу может просто посчастливиться завершить транзакцию до того, как другой попытается (и потерпит неудачу). Вот как это работает с jOOQ.
  В наших примерах данных таблица BOOK имеет специальный «системный» столбец с именем REC_TIMESTAMP .  Содержимое этого столбца полностью управляется jOOQ всякий раз, когда вы запускаете операцию CRUD на BookRecord , вам не нужно обновлять ее.  Рассмотрим следующий пример кода: 
| 
 1 
2 
3 
4 
5 
6 
7 
 | 
// Enable optimistic lockingDSLContext dsl = DSL.using(connection, new Settings().withExecuteWithOptimisticLocking(true));// Perform the CRUD with the above settingBookRecord book1 = dsl.selectFrom(BOOK).where(BOOK.ID.eq(1)).fetchOne();book1.setTitle("New Title");book1.store(); | 
  jOOQ теперь выполнит UPDATE которая также обновляет и проверяет значения REC_TIMESTAMP : 
| 
 1 
2 
3 
4 
 | 
update "PUBLIC"."BOOK"set    "PUBLIC"."BOOK"."TITLE" = 'New Title',       "PUBLIC"."BOOK"."REC_TIMESTAMP" = timestamp '2014-09-08 18:40:39.416'where ("PUBLIC"."BOOK"."ID" = 1 and "PUBLIC"."BOOK"."REC_TIMESTAMP" is null) | 
  Обратите внимание, как REC_TIMESTAMP установлен на текущее время в предложении SET , в то время как он также проверяется на NULL (начальное значение в примере базы данных) в WHERE . 
Если у нас есть два конкурирующих процесса (или секции кода в одном и том же процессе) для этого обновления, например:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
 | 
BookRecord book1 = dsl.selectFrom(BOOK).where(BOOK.ID.eq(1)).fetchOne();BookRecord book2 = dsl.selectFrom(BOOK).where(BOOK.ID.eq(1)).fetchOne();book1.setTitle("New Title");book1.store();book2.setTitle("Another Title");book2.store(); | 
  … Тогда мы увидим DataChangedException при втором вызове store() (сокращенная трассировка стека): 
| 
 1 
2 
3 
4 
5 
 | 
org.jooq.exception.DataChangedException: Database record has been changed or doesn't exist any longer    at org.jooq.impl.UpdatableRecordImpl.checkIfChanged(UpdatableRecordImpl.java:420)    at org.jooq.impl.UpdatableRecordImpl.storeUpdate(UpdatableRecordImpl.java:193)    at org.jooq.impl.UpdatableRecordImpl.store(UpdatableRecordImpl.java:129)    at org.jooq.impl.UpdatableRecordImpl.store(UpdatableRecordImpl.java:121) | 
  Оптимистическая блокировка применяется для операций UpdatableRecord , включая insert() , update() и delete() . 
jOOQ поддерживает три режима оптимистичной блокировки:
-   Использование выделенного столбца 
TIMESTAMPкоторый отслеживает дату изменения -   Использование выделенного столбца 
NUMBERкоторый отслеживает номер версии - Используя сравнение значений. Это значение по умолчанию, если для генератора кода не настроены временные метки или столбцы версий.