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

Автоматически сгенерированное поле для MongoDB с использованием Spring Boot

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

1. Обзор

В этом руководстве мы узнаем, как реализовать последовательное автоматически сгенерированное поле для MongoDB в Spring Boot.

Когда мы используем MongoDB в качестве базы данных для приложения Spring Boot, мы не можем использовать аннотацию @GeneratedValue в наших моделях, поскольку она недоступна. Следовательно, нам нужен метод для получения такого же эффекта, как если бы мы использовали JPA и базу данных SQL.

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

2. Зависимости

Давайте добавим в наш pom.xml следующие стартеры Spring-Boot :

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<versionId>2.2.2.RELEASE</versionId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<versionId>2.2.2.RELEASE</versionId>
</dependency>
</dependencies>

Последняя версия зависимостей управляется spring-boot-starter-parent .

3. Коллекции

Как обсуждалось в обзоре, мы создадим коллекцию, в которой будет храниться автоматически увеличивающаяся последовательность для других коллекций. Мы назовем эту коллекцию database_sequences. Его можно создать с помощью оболочки mongo или MongoDB Compass. Создадим соответствующий класс модели:

@Document(collection = "database_sequences")
public class DatabaseSequence {

@Id
private String id;

private long seq;

//getters and setters omitted
}

Давайте затем создадим коллекцию пользователей и соответствующий объект модели, в котором будут храниться сведения о людях, использующих нашу систему:

@Document(collection = "users")
public class User {

@Transient
public static final String SEQUENCE_NAME = "users_sequence";

@Id
private long id;

private String email;

//getters and setters omitted
}

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

Мы также аннотируем его с помощью @Transient , чтобы предотвратить его сохранение вместе с другими свойствами модели.

4. Создание новой записи

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

Давайте создадим SequenceGeneratorService с generateSequence() :

public long generateSequence(String seqName) {
DatabaseSequence counter = mongoOperations.findAndModify(query(where("_id").is(seqName)),
new Update().inc("seq",1), options().returnNew(true).upsert(true),
DatabaseSequence.class);
return !Objects.isNull(counter) ? counter.getSeq() : 1;
}

Теперь мы можем использовать generateSequence() при создании новой записи:

User user = new User();
user.setId(sequenceGenerator.generateSequence(User.SEQUENCE_NAME));
user.setEmail("john.doe@example.com");
userRepository.save(user);

Чтобы перечислить всех пользователей, мы будем использовать UserRepository :

List<User> storedUsers = userRepository.findAll();
storedUsers.forEach(System.out::println);

Как и сейчас, мы должны устанавливать поле id каждый раз, когда создаем новый экземпляр нашей модели. Мы можем обойти этот процесс, создав прослушиватель событий жизненного цикла Spring Data MongoDB.

Для этого мы создадим UserModelListener , который расширяет AbstractMongoEventListener<User> , а затем мы переопределим onBeforeConvert() :

@Override
public void onBeforeConvert(BeforeConvertEvent<User> event) {
if (event.getSource().getId() < 1) {
event.getSource().setId(sequenceGenerator.generateSequence(User.SEQUENCE_NAME));
}
}

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

5. Вывод

В заключение мы увидели, как генерировать последовательные автоматически увеличивающиеся значения для поля id и имитировать то же поведение, что и в базах данных SQL.

Hibernate по умолчанию использует аналогичный метод для генерации автоматически увеличивающихся значений.

Как обычно, полный исходный код доступен на Github .