1. 概要

このチュートリアルでは、Spring BootでMongoDBの順次自動生成フィールドを実装する方法を学習します。

Spring BootアプリケーションのデータベースとしてMongoDBを使用している場合、モデルで@GeneratedValueアノテーションを使用できないため、使用できません。 したがって、JPAとSQLデータベースを使用している場合と同じ効果を生み出す方法が必要です。

この問題の一般的な解決策は簡単です。 生成されたシーケンスを他のコレクション用に保存するコレクション(テーブル)を作成します。 新しいレコードの作成中に、それを使用して次の値をフェッチします。

2. 依存関係

次のspring-ブートスターターをpom.xmlに追加しましょう。

<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。 いずれかを使用して作成できますモンゴシェルまたはMongoDBコンパス。 対応するモデルクラスを作成しましょう。

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

    @Id
    private String id;

    private long seq;

    //getters and setters omitted
}

次に、 users コレクションと、対応するモデルオブジェクトを作成して、システムを使用しているユーザーの詳細を保存します。

@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
}

上記で作成したUserモデルでは、静的フィールド SEQUENCE_NAME、を追加しました。これは、usersコレクションの自動インクリメントシーケンスへの一意の参照です。

また、 @Transient で注釈を付けて、モデルの他のプロパティと一緒に永続化されないようにします。

4. 新しいレコードの作成

これまでに、必要なコレクションとモデルを作成しました。 次に、エンティティのidとして使用できる自動インクリメント値を生成するサービスを作成します。

generateSequence()を持つSequenceGeneratorServiceを作成しましょう。

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("[email protected]");
userRepository.save(user);

すべてのユーザーを一覧表示するには、UserRepositoryを使用します。

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

現在のように、モデルの新しいインスタンスを作成するたびにidフィールドを設定する必要があります。 Spring Data MongoDBライフサイクルイベントのリスナーを作成することで、このプロセスを回避できます。

そのために、 UserModelListener 伸びる AbstractMongoEventListener 次に、オーバーライドします onBeforeConvert()

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

これで、新しいユーザーを保存するたびに、 idが自動的に設定されます。

5. 結論

結論として、idフィールドの順次自動インクリメント値を生成し、SQLデータベースで見られるのと同じ動作をシミュレートする方法を見てきました。

Hibernateは、デフォルトで自動インクリメント値を生成するために同様の方法を使用します。

いつものように、完全なソースコードはGithubから入手できます。