I am using Spring-Boot 3.0.4 and I have upgraded Mongock from 4.3.8 to 5.2.2.
pom.xml snipped
<dependencies>
<dependency>
<groupId>io.mongock</groupId>
<artifactId>mongock-springboot</artifactId>
</dependency>
<dependency>
<groupId>io.mongock</groupId>
<artifactId>mongodb-springdata-v4-driver</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.mongock</groupId>
<artifactId>mongock-bom</artifactId>
<version>5.2.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
I have updated the old @Changelog and @ChangeSet annotations as explained in the doc https://docs.mongock.io/v5/migration/index.html, and similarly for the transactions https://docs.mongock.io/v5/features/transactions/index.html
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.MongoTransactionManager;
@Configuration
public class DatabaseTransactionConfiguration {
@Bean
MongoTransactionManager transactionManager(MongoDatabaseFactory factory) {
return new MongoTransactionManager(factory);
}
}
package org.project.configuration.database.migration;
import io.mongock.api.annotations.*;
import org.project.domain.Questionnaire;
import org.project.service.QuestionnaireService;
import org.springframework.data.mongodb.core.MongoTemplate;
@ChangeUnit(id="questionnaire-initializer", order = "6", author = "dev", runAlways = true)
public class CU06_Questionnaire {
@BeforeExecution
public void beforeExecution(MongoTemplate mongoTemplate) {
if (!mongoTemplate.collectionExists(Questionnaire.class)) {
mongoTemplate.createCollection(Questionnaire.class);
}
}
@RollbackBeforeExecution
public void rollbackBeforeExecution(MongoTemplate mongoTemplate) {
}
@Execution
public void execution(QuestionnaireService questionnaireService) {
Questionnaire questionnaire = questionnaireService.loadQuestionnaireData();
questionnaireService.save(questionnaire);
}
@RollbackExecution
public void rollbackExecution(QuestionnaireService questionnaireService) {
Questionnaire questionnaire = questionnaireService.loadQuestionnaireData();
questionnaireService.delete(questionnaire);
}
}
application.yaml
spring:
data:
mongodb:
host: ${MONGODB_HOST:localhost}
port: ${MONGODB_PORT:27017}
database: ${MONGODB_DATABASE:project}
auto-index-creation: true
profiles:
active: ${SPRING_PROFILES_ACTIVE:dev}
mongock:
migration-scan-package: org.project.configuration.database.migration
transaction-enabled: true
however I'm having the following error when starting the application:
io.mongock.api.exception.MongockException: Error in
method[CU06_OTQuestionnaire.execution] : Command failed with error 251
(NoSuchTransaction): 'Transaction with { txnNumber: 30 } has been aborted.' on server
localhost:27017. The full response is {"errorLabels": ["TransientTransactionError"],
"ok": 0.0, "errmsg": "Transaction with { txnNumber: 30 } has been aborted.", "code":
251, "codeName": "NoSuchTransaction", "$clusterTime": {"clusterTime": {"$timestamp":
{"t": 1679076061, "i": 99}}, "signature": {"hash": {"$binary": {"base64":
"AAAAAAAAAAAAAAAAAAAAAAAAAAA=", "subType": "00"}}, "keyId": 0}}, "operationTime":
{"$timestamp": {"t": 1679076061, "i": 99}}}
What am I missing that causes this exception between Mongock and the Transactios?
Update
As suggested I fixed the Mongock Runner dependency:
<dependency>
<groupId>io.mongock</groupId>
<artifactId>mongock-springboot-v3</artifactId>
</dependency>
and I improved the MongoTransactionManager @Bean too:
@Bean
public MongoTransactionManager transactionManager(MongoTemplate mongoTemplate) {
TransactionOptions transactionalOptions = TransactionOptions.builder()
.readConcern(ReadConcern.MAJORITY)
.readPreference(ReadPreference.primary())
.writeConcern(WriteConcern.MAJORITY.withJournal(true))
.build();
return new MongoTransactionManager(mongoTemplate.getMongoDatabaseFactory(), transactionalOptions);
}
However, the exception remains, but only with the Questionnaire class and the corresponding @ChangeUnit. If I comment out the @ChangeUnit annotation on the CU06_Questionnaire migration class, all the other migrations work without any problem.
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.project.domain.enumeration.QuestionnaireType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
@Data
@Builder
@Document
@NoArgsConstructor
@AllArgsConstructor
public class Questionnaire {
@Id
private String id;
@Transient
@JsonIgnore
@Builder.Default
private Class<String> idType = String.class;
private String name;
private String description;
@Indexed(unique = true)
private QuestionnaireType type;
private List<String> questions;
}
@RequiredArgsConstructor
@Getter
public enum QuestionnaireType {
A(0), B(1);
private final int value;
}
And this is the corresponding JSON that I'm loading:
{
"id": Questionnaire-001",
"name": "Questionnaire 001",
"description": "Questionnaire to ...",
"type": "A",
"questions": [
"Question-0000",
"Question-0001",
"Question-0002",
"Question-0003",
"Question-0004",
"Question-0005",
"Question-0006",
"Question-0007",
"Question-0008",
"Question-0009",
"Question-0010"
]
}
Minimal Non-Working Example
Mongock provides two specific modules to work with springboot (v3) and springdata (v4). You need to use the springboot v3 dependency as follow:
This sample project is currently working with those dependencies.
UPDATE:
After review your Minimal Non-Working Example, the error is due to Mongock is generating a proxy instance for your injected
QuestionnaireServicedependency and its return valueQuestionnaire. In this case, although proxing theQuestionnaireServiceinjection is highly recommended(so the lock is guaranteed), the actual returned items(Questionnaire) don't need to and actually, in this case, it's producing the error. So the suggested solution is to annotate your dependencyQuestionnaireServiceas follow:Please refer to our official documentation about Mongock's proxy mechanism and how to handle it at the following link:
Mongock Proxies