Статьи

Использование jOOQ с Spring: CRUD

jOOQ — это библиотека, которая помогает нам вернуть контроль над нашим SQL. Он может генерировать код из нашей базы данных и позволяет нам создавать безопасные запросы к базе данных, используя его свободный API.

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

Теперь мы готовы сделать один шаг вперед и узнать, как мы можем создавать безопасные запросы с помощью jOOQ. В этом блоге описывается, как мы можем добавить операции CRUD в простое приложение, которое управляет записями задач.

Давайте начнем.

Дополнительное чтение:

  • Использование jOOQ с Spring: Конфигурация — это первая часть этого руководства, в которой описано, что вы можете настроить контекст приложения Spring, которое использует jOOQ. Вы можете понять этот пост, не читая первую часть этого руководства, но если вы действительно хотите использовать jOOQ в приложении на базе Spring, я рекомендую вам прочитать и первую часть этого руководства.
  • Использование jOOQ с Spring: генерация кода — это вторая часть этого учебника, и в нем описывается, как мы можем выполнить реинжиниринг нашей базы данных и создать классы запросов jOOQ, которые представляют разные таблицы базы данных, записи и так далее. Поскольку эти классы являются строительными блоками безопасных типов запросов SQL, я рекомендую вам прочитать вторую часть этого руководства перед прочтением этого сообщения в блоге .

Создание класса Todo

Давайте начнем с создания класса, который содержит информацию об одной записи todo. Этот класс имеет следующие поля:

  • Поле id содержит идентификатор записи todo.
  • Поле creationTime содержит метку времени, которая описывает, когда запись todo была сохранена в первый раз.
  • Поле описания содержит описание записи todo.
  • Поле ModificationTime содержит метку времени, которая описывает, когда запись todo была обновлена.
  • Поле заголовка содержит заголовок записи задачи.

Название этого относительно простого класса — Todo , и оно следует трем принципам, которые описаны ниже:

Исходный код класса Todo выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.joda.time.LocalDateTime;
 
import java.sql.Timestamp;
 
public class Todo {
 
    private final Long id;
 
    private final LocalDateTime creationTime;
 
    private final String description;
 
    private final LocalDateTime modificationTime;
 
    private final String title;
 
    private Todo(Builder builder) {
        this.id = builder.id;
 
        LocalDateTime creationTime = null;
        if (builder.creationTime != null) {
            creationTime = new LocalDateTime(builder.creationTime);
        }
        this.creationTime = creationTime;
 
        this.description = builder.description;
 
        LocalDateTime modificationTime = null;
        if (builder.modificationTime != null) {
            modificationTime = new LocalDateTime(builder.modificationTime);
        }
        this.modificationTime = modificationTime;
 
        this.title = builder.title;
    }
 
    public static Builder getBuilder(String title) {
        return new Builder(title);
    }
 
    //Getters are omitted for the sake of clarity.
 
    public static class Builder {
 
        private Long id;
 
        private Timestamp creationTime;
 
        private String description;
 
        private Timestamp modificationTime;
 
        private String title;
 
        public Builder(String title) {
            this.title = title;
        }
 
        public Builder description(String description) {
            this.description = description;
            return this;
        }
 
        public Builder creationTime(Timestamp creationTime) {
            this.creationTime = creationTime;
            return this;
        }
 
        public Builder id(Long id) {
            this.id = id;
            return this;
        }
 
        public Builder modificationTime(Timestamp modificationTime) {
            this.modificationTime = modificationTime;
            return this;
        }
 
        public Todo build() {
            Todo created = new Todo(this);
 
            String title = created.getTitle();
 
            if (title == null || title.length() == 0) {
                throw new IllegalStateException("title cannot be null or empty");
            }
 
            return created;
        }
    }
}

Давайте выясним, почему нам нужно получить текущую дату и время, и, что более важно, как это лучше всего сделать.

Получение текущей даты и времени

Поскольку время создания и время модификации каждой записи todo хранятся в базе данных, нам нужен способ получения текущей даты и времени. Конечно, мы могли бы просто создать эту информацию в нашем хранилище. Проблема в том, что если бы мы сделали это, мы не смогли бы написать автоматические тесты, которые гарантировали бы, что время создания и время модификации установлены правильно (мы не можем написать утверждения для этих полей, потому что их значения зависят от текущего времени) ,

Вот почему нам нужно создать отдельный компонент, который отвечает за возврат текущей даты и времени. Интерфейс DateTimeService объявляет два метода, которые описаны ниже:

  • Метод getCurrentDateTime () возвращает текущую дату и время в виде объекта LocalDateTime .
  • Метод getCurrentTimestamp () возвращает текущую дату и время в виде объекта Timestamp .

Исходный код интерфейса DateTimeService выглядит следующим образом:

1
2
3
4
5
6
7
8
9
import org.joda.time.LocalDateTime;
import java.sql.Timestamp;
 
public interface DateTimeService {
 
    public LocalDateTime getCurrentDateTime();
 
    public Timestamp getCurrentTimestamp();
}

Поскольку наше приложение интересуется «реальным» временем, мы должны реализовать этот интерфейс и создать компонент, который возвращает реальную дату и время. Мы можем сделать это, выполнив следующие действия:

  1. Создайте класс CurrentTimeDateTimeService, который реализует интерфейс DateTimeService .
  2. Пометьте класс аннотацией @Profile и задайте для имени профиля значение «application». Это означает, что компонент может быть зарегистрирован в контейнере Spring, когда активным профилем Spring является «приложение».
  3. Аннотируйте класс с помощью аннотации @Component . Это гарантирует, что класс найден во время сканирования пути к классам.
  4. Реализуйте методы, объявленные в интерфейсе DateTimeService . Каждый метод должен возвращать текущую дату и время.

Исходный код CurrentTimeDateTimeService выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
import org.joda.time.LocalDateTime;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
 
import java.sql.Timestamp;
 
@Profile("application")
@Component
public class CurrentTimeDateTimeService implements DateTimeService {
 
    @Override
    public LocalDateTime getCurrentDateTime() {
        return LocalDateTime.now();
    }
 
    @Override
    public Timestamp getCurrentTimestamp() {
        return new Timestamp(System.currentTimeMillis());
    }
}

Давайте перейдем к реализации уровня репозитория нашего примера приложения.

Реализация уровня репозитория

Сначала мы создаем интерфейс репозитория, который обеспечивает операции CRUD для записей todo. Этот интерфейс объявляет пять методов, которые описаны ниже:

  • Метод Todo add (Todo todoEntry) сохраняет новую запись todo в базе данных и возвращает информацию о сохраненной записи todo.
  • Метод Todo delete (Long id) удаляет запись todo и возвращает удаленную запись todo.
  • Метод List findAll () возвращает все записи дел, найденные в базе данных.
  • Todo findById (Long id) возвращает информацию об одной записи todo.
  • Обновление Todo (Todo todoEntry) обновляет информацию о записи todo и возвращает обновленную запись todo.

Исходный код интерфейса TodoRepository выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
import java.util.List;
 
public interface TodoRepository {
 
    public Todo add(Todo todoEntry);
 
    public Todo delete(Long id);
 
    public List<Todo> findAll();
 
    public Todo findById(Long id);
 
    public Todo update(Todo todoEntry);
}

Далее мы должны реализовать интерфейс TodoRepository . Когда мы делаем это, мы должны следовать следующему правилу:

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

Как правило, сервисный уровень действует как граница транзакции, и каждый вызов репозитория jOOQ должен выполняться внутри транзакции. Однако, поскольку программисты тоже допускают ошибки, мы не можем поверить, что это так. Вот почему мы должны аннотировать класс репозитория или его методы аннотацией @Transactional .

Теперь, когда мы это поняли, мы готовы создать наш класс репозитория.

Создание класса репозитория

Мы можем создать «скелет» нашего класса репозитория, выполнив следующие шаги:

  1. Создайте класс JOOQTodoRepository и реализуйте интерфейс TodoRepository .
  2. Аннотируйте класс с помощью аннотации @Repository . Это гарантирует, что класс будет найден во время сканирования пути к классам.
  3. Добавьте поле DateTimeService в созданный класс. Как мы помним, интерфейс DateTimeService объявляет методы, которые используются для получения текущей даты и времени.
  4. Добавьте поле DSLContext в созданный класс. Этот интерфейс действует как точка входа в API jOOQ, и мы можем создавать наши SQL-запросы, используя его.
  5. Добавьте открытый конструктор к созданному классу и аннотируйте конструктор аннотацией @Autowired . Это гарантирует, что зависимости нашего репозитория внедряются с помощью инжектора конструктора.
  6. Добавьте закрытый метод Todo convertQueryResultToModelObject (TodosRecord queryResult) в класс репозитория. Этот служебный метод используется открытыми методами нашего класса репозитория. Реализуйте этот метод, выполнив следующие действия:
    1. Создайте новый объект Todo , используя информацию об объекте TodosRecord, заданную в качестве параметра метода.
    2. Вернуть созданный объект.

Соответствующая часть класса JOOQTodoRepository выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
 
 
@Repository
public class JOOQTodoRepository implements TodoRepository {
 
    private final DateTimeService dateTimeService;
 
    private final DSLContext jooq;
 
    @Autowired
    public JOOQTodoRepository(DateTimeService dateTimeService, DSLContext jooq) {
        this.dateTimeService = dateTimeService;
        this.jooq = jooq;
    }
 
    private Todo convertQueryResultToModelObject(TodosRecord queryResult) {
        return Todo.getBuilder(queryResult.getTitle())
                .creationTime(queryResult.getCreationTime())
                .description(queryResult.getDescription())
                .id(queryResult.getId())
                .modificationTime(queryResult.getModificationTime())
                .build();
    }
}

Давайте продолжим и реализуем методы, которые обеспечивают операции CRUD для записей todo.

Добавление новой записи Todo

Открытый метод Todo add (Todo todoEntry) интерфейса TodoRepository используется для добавления новых записей todo в базу данных. Мы можем реализовать этот метод, выполнив следующие действия:

  1. Добавьте приватный метод TodosRecord createRecord (Todo todoEntry) в класс репозитория и реализуйте этот метод, выполнив следующие шаги:
    1. Получите текущую дату и время, вызвав метод getCurrentTimestamp () интерфейса DateTimeService .
    2. Создайте новый объект TodosRecord и установите значения его полей, используя информацию об объекте Todo, заданную в качестве параметра метода.
    3. Вернуть созданный объект TodosRecord .
  2. Добавьте метод add () в класс JOOQTodoRepository и аннотируйте метод аннотацией @Transactional . Это гарантирует, что оператор INSERT выполняется внутри транзакции чтения-записи.
  3. Реализуйте метод add () , выполнив следующие действия:
    1. Добавьте новую запись todo в базу данных, выполнив следующие действия:
      1. Создайте новый оператор INSERT , вызвав метод insertInto (таблица таблицы) интерфейса DSLContext и укажите, что вы хотите вставить информацию в таблицу задач .
      2. Создайте новый объект TodosRecord , вызвав метод createRecord () . Передайте объект Todo в качестве параметра метода.
      3. Установите вставленную информацию, вызвав метод set (Record record) интерфейса InsertSetStep . Передайте созданный объект TodosRecord в качестве параметра метода.
      4. Убедитесь, что запрос INSERT возвращает все вставленные поля, вызвав метод returning () интерфейса InsertReturningStep .
      5. Получите объект TodosRecord, который содержит значения всех вставленных полей, вызвав метод fetchOne () интерфейса InsertResultStep .
    2. Преобразуйте объект TodosRecord, возвращенный инструкцией INSERT, в объект Todo , вызвав метод convertQueryResultToModelObject () .
    3. Вернуть созданный объект Todo .

Соответствующая часть класса JOOQTodoRepository выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord;
import org.jooq.DSLContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
 
import java.sql.Timestamp;
 
import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;
 
@Repository
public class JOOQTodoRepository implements TodoRepository {
 
    private final DateTimeService dateTimeService;
 
    private final DSLContext jooq;
 
    //The constructor is omitted for the sake of clarity
 
    @Transactional
    @Override
    public Todo add(Todo todoEntry) {
        TodosRecord persisted = jooq.insertInto(TODOS)
                .set(createRecord(todoEntry))
                .returning()
                .fetchOne();
 
        return convertQueryResultToModelObject(persisted);
    }
 
    private TodosRecord createRecord(Todo todoEntry) {
        Timestamp currentTime = dateTimeService.getCurrentTimestamp();
 
        TodosRecord record = new TodosRecord();
        record.setCreationTime(currentTime);
        record.setDescription(todoEntry.getDescription());
        record.setModificationTime(currentTime);
        record.setTitle(todoEntry.getTitle());
 
        return record;
    }
 
    private Todo convertQueryResultToModelObject(TodosRecord queryResult) {
        return Todo.getBuilder(queryResult.getTitle())
                .creationTime(queryResult.getCreationTime())
                .description(queryResult.getDescription())
                .id(queryResult.getId())
                .modificationTime(queryResult.getModificationTime())
                .build();
    }
}

Раздел 4.3.3. Инструкция INSERT справочного руководства jOOQ предоставляет дополнительную информацию о вставке данных в базу данных.

Давайте продолжим и выясним, как мы можем найти все записи, которые хранятся в базе данных.

Поиск всех записей Todo

Открытый метод List findAll () интерфейса TodoRepository возвращает все записи todo, которые хранятся в базе данных. Мы можем реализовать этот метод, выполнив следующие действия:

  1. Добавьте метод findAll () в класс репозитория и аннотируйте метод аннотацией @Transactional . Установите для его атрибута readOnly значение true . Это гарантирует, что инструкция SELECT выполняется внутри транзакции только для чтения.
  2. Получить все записи задач из базы данных, выполнив следующие действия:
    1. Создайте новый оператор SELECT , вызвав метод selectFrom (таблица таблиц) интерфейса DSLContext, и укажите, что вы хотите выбрать информацию из таблицы задач .
    2. Получите список объектов TodosRecord , вызвав метод fetchInto (тип класса) интерфейса ResultQuery .
  3. Итерируйте возвращенный список объектов TodosRecord и преобразуйте каждый объект TodosRecord в объект Todo , вызывая метод convertQueryResultToModelObject () . Добавьте каждый объект Todo в список объектов Todo .
  4. Вернуть список, который содержит найденные объекты Todo .

Соответствующая часть класса JOOQTodoRepository выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord;
import org.jooq.DSLContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
 
import java.util.ArrayList;
import java.util.List;
 
import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;
 
@Repository
public class JOOQTodoRepository implements TodoRepository {
 
    private final DSLContext jooq;
 
    //The constructor is omitted for the sake of clarity
 
    @Transactional(readOnly = true)
    @Override
    public List<Todo> findAll() {
        List<Todo> todoEntries = new ArrayList<>();
 
        List<TodosRecord> queryResults = jooq.selectFrom(TODOS).fetchInto(TodosRecord.class);
 
        for (TodosRecord queryResult: queryResults) {
            Todo todoEntry = convertQueryResultToModelObject(queryResult);
            todoEntries.add(todoEntry);
        }
 
        return todoEntries;
    }
 
    private Todo convertQueryResultToModelObject(TodosRecord queryResult) {
        return Todo.getBuilder(queryResult.getTitle())
                .creationTime(queryResult.getCreationTime())
                .description(queryResult.getDescription())
                .id(queryResult.getId())
                .modificationTime(queryResult.getModificationTime())
                .build();
    }
}

Раздел 4.3.2. Оператор SELECT справочного руководства jOOQ предоставляет дополнительную информацию о выборе информации из базы данных.

Далее мы узнаем, как мы можем получить одну запись todo из базы данных.

Поиск единственной записи Todo

Открытый метод Todo findById (Long id) интерфейса TodoRepository возвращает информацию об одной записи todo. Мы можем реализовать этот метод, выполнив следующие действия:

  1. Добавьте метод findById () в класс репозитория и аннотируйте метод аннотацией @Transactional . Установите для его атрибута readOnly значение true. Это гарантирует, что инструкция SELECT выполняется внутри транзакции только для чтения.
  2. Получите информацию об одной записи todo из базы данных, выполнив следующие действия:
    1. Создайте новый оператор SELECT , вызвав метод selectFrom (таблица таблиц) интерфейса DSLContext, и укажите, что вы хотите выбрать информацию из таблицы задач .
    2. Укажите предложение WHERE оператора SELECT , вызвав метод where (условия сбора данных) интерфейса SelectWhereStep . Убедитесь, что инструкция SELECT возвращает только запись todo, идентификатор которой был задан в качестве параметра метода.
    3. Получите объект TodosRecord , вызвав метод fetchOne () интерфейса ResultQuery .
  3. Если возвращенный объект TodosRecord имеет значение null, это означает, что не было найдено ни одной записи todo с данным идентификатором. Если это так, создайте новое исключение TodoNotFoundException .
  4. Преобразуйте объект TodosRecord, возвращенный инструкцией SELECT, в объект Todo , вызвав метод convertQueryResultToModelObject () .
  5. Вернуть созданный объект Todo .

Соответствующая часть JOOQTodoRepository выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord;
import org.jooq.DSLContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
 
import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;
 
@Repository
public class JOOQTodoRepository implements TodoRepository {
 
    private final DSLContext jooq;
 
    //The constructor is omitted for the sake of clarity.
 
    @Transactional(readOnly = true)
    @Override
    public Todo findById(Long id) {
        TodosRecord queryResult = jooq.selectFrom(TODOS)
                .where(TODOS.ID.equal(id))
                .fetchOne();
 
        if (queryResult == null) {
            throw new TodoNotFoundException("No todo entry found with id: " + id);
        }
 
        return convertQueryResultToModelObject(queryResult);
    }
 
    private Todo convertQueryResultToModelObject(TodosRecord queryResult) {
        return Todo.getBuilder(queryResult.getTitle())
                .creationTime(queryResult.getCreationTime())
                .description(queryResult.getDescription())
                .id(queryResult.getId())
                .modificationTime(queryResult.getModificationTime())
                .build();
    }
}

Раздел 4.3.2. Оператор SELECT справочного руководства jOOQ предоставляет дополнительную информацию о выборе информации из базы данных.

Давайте выясним, как мы можем удалить запись todo из базы данных.

Удаление записи Todo

Открытый метод Todo delete (Long id) интерфейса TodoRepository используется для удаления записи todo из базы данных. Мы можем реализовать этот метод, выполнив следующие действия:

  1. Добавьте метод delete () в класс репозитория и аннотируйте метод аннотацией @Transactional . Это гарантирует, что оператор DELETE выполняется внутри транзакции чтения-записи.
  2. Реализуйте этот метод, выполнив следующие действия:
    1. Найдите удаленный объект Todo , вызвав метод findById (Long id) . Передайте идентификатор удаленной записи todo в качестве параметра метода.
    2. Удалите запись todo из базы данных, выполнив следующие действия:
      1. Создайте новый оператор DELETE , вызвав метод delete (таблица таблиц) интерфейса DSLContext, и укажите, что вы хотите удалить информацию из таблицы задач .
      2. Укажите предложение WHERE оператора DELETE , вызвав метод where (условия сбора данных) интерфейса DeleteWhereStep . Убедитесь, что инструкция DELETE удаляет запись todo, идентификатор которой был задан в качестве параметра метода.
      3. Выполните инструкцию DELETE , вызвав метод execute () интерфейса Query .
    3. Вернуть информацию об удаленной записи todo.

Соответствующая часть класса JOOQTodoRepository выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord;
import org.jooq.DSLContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
 
import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;
 
@Repository
public class JOOQTodoRepository implements TodoRepository {
 
    private final DSLContext jooq;
 
    //The constructor is omitted for the sake of clarity
 
    @Transactional
    @Override
    public Todo delete(Long id) {
        Todo deleted = findById(id);
 
        int deletedRecordCount = jooq.delete(TODOS)
                .where(TODOS.ID.equal(id))
                .execute();
 
        return deleted;
    }
}

Раздел 4.3.5. Оператор DELETE справочного руководства jOOQ предоставляет дополнительную информацию об удалении данных из базы данных.

Давайте продолжим и выясним, как мы можем обновить информацию о существующей записи todo.

Обновление существующей записи Todo

Открытый метод обновления Todo (Todo todoEntry) интерфейса TodoRepository обновляет информацию о существующей записи todo. Мы можем реализовать этот метод, выполнив следующие действия:

  1. Добавьте метод update () в класс репозитория и аннотируйте метод аннотацией @Transactional . Это гарантирует, что инструкция UPDATE выполняется внутри транзакции чтения-записи.
  2. Получите текущую дату и время, вызвав метод getCurrentTimestamp () интерфейса DateTimeService .
  3. Обновите информацию о записи todo, выполнив следующие действия:
    1. Создайте новый оператор UPDATE , вызвав метод update (таблица таблиц) интерфейса DSLContext, и укажите, что вы хотите обновить информацию, найденную в таблице задач .
    2. Установите новое описание, время модификации и заголовок, вызвав метод set (поле Field, значение T) интерфейса UpdateSetStep .
    3. Укажите предложение WHERE оператора UPDATE , вызвав метод where (условия сбора данных) интерфейса UpdateWhereStep . Убедитесь, что инструкция UPDATE обновляет запись todo, идентификатор которой найден из объекта Todo, заданного в качестве параметра метода.
    4. Выполните инструкцию UPDATE , вызвав метод execute () интерфейса Query .
  4. Получите информацию об обновленной записи todo, вызвав метод findById () . Передайте идентификатор обновленной записи todo в качестве параметра метода.
  5. Вернуть информацию об обновленной записи todo.

Соответствующая часть класса JOOQTodoRepository выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import org.jooq.DSLContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
 
import java.sql.Timestamp;
 
import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;
 
@Repository
public class JOOQTodoRepository implements TodoRepository {
 
    private final DateTimeService dateTimeService;
 
    private final DSLContext jooq;
 
    //The constructor is omitted for the sake of clarity.
 
    @Transactional
    @Override
    public Todo update(Todo todoEntry) {
        Timestamp currentTime = dateTimeService.getCurrentTimestamp();
        
        int updatedRecordCount = jooq.update(TODOS)
                .set(TODOS.DESCRIPTION, todoEntry.getDescription())
                .set(TODOS.MODIFICATION_TIME, currentTime)
                .set(TODOS.TITLE, todoEntry.getTitle())
                .where(TODOS.ID.equal(todoEntry.getId()))
                .execute();
 
        return findById(todoEntry.getId());
    }
}

Это все люди. Давайте подведем итог тому, что мы узнали из этого поста в блоге.

Резюме

Теперь мы внедрили операции CRUD для записей todo. Этот урок научил нас трем вещам:

  • Мы узнали, как мы можем получить текущую дату и время таким образом, чтобы мы не писали автоматические тесты для нашего примера приложения.
  • Мы узнали, как мы можем гарантировать, что все запросы к базе данных, выполняемые jOOQ, выполняются внутри транзакции.
  • Мы узнали, как мы можем создавать операторы INSERT , SELECT , DELETE и UPDATE , используя jOOQ API.

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

  • Пример приложения этого блога доступен на Github (внешний интерфейс еще не реализован).