Spring Data MongoDBトランザクション

Spring Data MongoDBトランザクション

1. 概要

4.0リリースから、MongoDBはマルチドキュメントACIDトランザクションをサポートします。 そして、Spring Data Lovelace now provides support for these native MongoDB transactions

このチュートリアルでは、同期トランザクションとリアクティブトランザクションに対するSpring DataMongoDBのサポートについて説明します。

また、非ネイティブトランザクションのサポートに関するSpring DataTransactionTemplateについても見ていきます。

このSpringDataモジュールの概要については、introductory write-upをご覧ください。

2. MongoDB4.0をセットアップする

まず、新しいネイティブトランザクションのサポートを試すために、最新のMongoDBをセットアップする必要があります。

開始するには、MongoDB Download Centerから最新バージョンをダウンロードする必要があります。

次に、コマンドラインを使用してmongodサービスを開始します。

mongod --replSet rs0

最後に、レプリカセットを開始します(まだ開始されていない場合)。

mongo --eval "rs.initiate()"

MongoDBは現在、レプリカセットを介したトランザクションをサポートしていることに注意してください。

3. Mavenの構成

次に、次の依存関係をpom.xmlに追加する必要があります。


    org.springframework.data
    spring-data-mongodb
    2.1.0.RELEASE



    org.springframework.data
    spring-data-releasetrain
    Lovelace-M3
    pom
    import

マイルストーンリポジトリをpom.xmlにも追加する必要があることに注意してください。


    
        spring-milestones
        Spring Milestones
        https://repo.spring.io/milestone
        
            false
        
    

ライブラリの最新リリースは、Central Repositoryにあります。

4. MongoDBの構成

それでは、構成を見てみましょう。

@Configuration
@EnableMongoRepositories(basePackages = "com.example.repository")
public class MongoTransactionConfig extends AbstractMongoConfiguration{

    @Bean
    MongoTransactionManager transactionManager(MongoDbFactory dbFactory) {
        return new MongoTransactionManager(dbFactory);
    }

    @Override
    protected String getDatabaseName() {
        return "test";
    }

    @Override
    public MongoClient mongoClient() {
        return new MongoClient("127.0.0.1", 27017);
    }
}

デフォルトでは無効になっているため、ネイティブMongoDBトランザクションを有効にするための構成のwe need to register MongoTransactionManagerに注意してください。

5. 同期トランザクション

構成が完了したら、ネイティブのMongoDBトランザクションを使用するために必要なことはannotate our method with*@Transactional*.だけです。

注釈付きメソッド内のすべてが1つのトランザクションで実行されます。

@Test
@Transactional
public void whenPerformMongoTransaction_thenSuccess() {
    userRepository.save(new User("John", 30));
    userRepository.save(new User("Ringo", 35));
    Query query = new Query().addCriteria(Criteria.where("name").is("John"));
    List users = mongoTemplate.find(query, User.class);

    assertThat(users.size(), is(1));
}

マルチドキュメントトランザクション内ではlistCollectionsコマンドを使用できないことに注意してください。例:

@Test(expected = MongoTransactionException.class)
@Transactional
public void whenListCollectionDuringMongoTransaction_thenException() {
    if (mongoTemplate.collectionExists(User.class)) {
        mongoTemplate.save(new User("John", 30));
        mongoTemplate.save(new User("Ringo", 35));
    }
}

この例では、collectionExists()メソッドを使用したため、MongoTransactionExceptionがスローされます。

また、マルチドキュメントトランザクション内でcountを実行することはできません。

@Test(expected = MongoCommandException.class)
@Transactional
public void whenCountDuringMongoTransaction_thenException() {
    userRepository.save(new User("John", 30));
    userRepository.save(new User("Ringo", 35));
    userRepository.count();
}

ただし、単純なクエリでこの問題を回避し、結果のリストのサイズを取得できます。

@Test
@Transactional
public void whenQueryDuringMongoTransaction_thenSuccess() {
    userRepository.save(new User("Jane", 20));
    userRepository.save(new User("Nick", 33));
    List users = mongoTemplate.find(new Query(), User.class);

    assertTrue(users.size() > 1);
}

6. TransactionTemplate

Spring Dataが新しいMongoDBネイティブトランザクションをサポートする方法を見ました。 さらに、Spring Dataは非ネイティブオプションも提供します。

We can perform non-native transactions using Spring Data TransactionTemplate

@Test
public void givenTransactionTemplate_whenPerformTransaction_thenSuccess() {
    mongoTemplate.setSessionSynchronization(SessionSynchronization.ALWAYS);

    TransactionTemplate transactionTemplate = new TransactionTemplate(mongoTransactionManager);
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            mongoTemplate.insert(new User("Kim", 20));
            mongoTemplate.insert(new User("Jack", 45));
        };
    });

    Query query = new Query().addCriteria(Criteria.where("name").is("Jack"));
    List users = mongoTemplate.find(query, User.class);

    assertThat(users.size(), is(1));
}

非ネイティブのSpringDataトランザクションを使用するには、SessionSynchronizationALWAYSに設定する必要があります。

7. リアクティブトランザクション

最後に、Spring Data support for MongoDB reactive transactionsを見てみましょう。

リアクティブMongoDBを使用するには、pom.xmlにさらにいくつかの依存関係を追加する必要があります。


    org.mongodb
    mongodb-driver-reactivestreams
    1.9.2



    io.projectreactor
    reactor-test
    3.2.0.RELEASE
    test

mongodb-driver-reactivestreamsおよびreactor-testの依存関係は、MavenCentralで利用できます。

そしてもちろん、Reactive MongoDBを構成する必要があります。

@Configuration
@EnableReactiveMongoRepositories(basePackages
  = "com.example.reactive.repository")
public class MongoReactiveConfig
  extends AbstractReactiveMongoConfiguration {

    @Override
    public MongoClient reactiveMongoClient() {
        return MongoClients.create();
    }

    @Override
    protected String getDatabaseName() {
        return "reactive";
    }
}

リアクティブMongoDBでトランザクションを使用するには、ReactiveMongoOperationsinTransaction()メソッドを使用する必要があります。

@Autowired
private ReactiveMongoOperations reactiveOps;

@Test
public void whenPerformTransaction_thenSuccess() {
    User user1 = new User("Jane", 23);
    User user2 = new User("John", 34);
    reactiveOps.inTransaction()
      .execute(action -> action.insert(user1)
      .then(action.insert(user2)));
}

Spring Dataのリアクティブリポジトリの詳細については、hereを参照してください。

8. 結論

この記事では、Spring Dataを使用してネイティブおよび非ネイティブのMongoDBトランザクションを使用する方法を学びました。

例の完全なソースコードは利用可能ですover on GitHub.