使用 MongoDb 4.0.x,您可以使用事务。如果您使用以下版本,则必须实现两阶段提交。
注意:MongoDb 仅允许您在拥有 ReplicaSet 时使用事务。
要同时为 JPA 和 MongoDb 使用事务,您必须使用 ChainedTransactionManager。过程是:
- 创建 Jpa 事务管理器
- 创建 MongoDb 事务管理器
- 创建将使用上述两个的 ChainedTransactionManager
我的 conf 看起来像这样(我不使用 spring boot,但它应该是等效的):
Jpa 配置
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories("com....")
public class HibernateConfig {
//define entity manager, data source and all the stuff needed for your DB
@Bean("jpaTransactionManager")
public JpaTransactionManager transactionManager() throws NamingException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
//transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
MongoDb 配置
@Configuration
@EnableMongoRepositories(basePackages = "com....")
public class MongoDbConf extends AbstractMongoClientConfiguration {
private final Environment environment;
@Autowired
public MongoDbConf(Environment environment) {
this.environment = environment;
}
@Override
public MongoClient mongoClient() {
String connectionString = environment.getProperty("mongodb.connectionString");
if(StringUtils.isBlank(connectionString))
throw new IllegalArgumentException("No connection string to initialize mongo client");
return MongoClients.create(
MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.applicationName("MY_APP")
.build());
}
@Override
protected String getDatabaseName() {
return environment.getProperty("mongodb.database", "myDB");
}
@Bean("mongoDbTransactionManager")
public MongoTransactionManager transactionManager(MongoDbFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
}
ChainedTransactionManager 配置
@Configuration
public class ChainedTransactionConf {
private MongoTransactionManager mongoTransactionManager;
private JpaTransactionManager jpaTransactionManager;
@Autowired
public ChainedTransactionConf(MongoTransactionManager mongoTransactionManager, JpaTransactionManager jpaTransactionManager) {
this.mongoTransactionManager = mongoTransactionManager;
this.jpaTransactionManager = jpaTransactionManager;
}
@Bean("chainedTransactionManager")
public PlatformTransactionManager getTransactionManager() {
ChainedTransactionManager transactionManager = new ChainedTransactionManager(jpaTransactionManager, mongoTransactionManager);
return transactionManager;
}
}
mongoDb 存储库示例
@Service
public class MongoDbRepositoryImpl implements MongoDbRepository {
private static final Logger logger = Logger.getLogger(MongoDbRepositoryImpl.class);
//MongoOperations will handle a mongo session
private final MongoOperations operations;
@Autowired
public MongoDbRepositoryImpl(MongoOperations operations) {
this.operations = operations;
}
@Override
public void insertData(Document document) {
MongoCollection<Document> collection = operations.getCollection("myCollection");
collection.insertOne(document);
}
在您的服务中使用事务
@Service
public class DocumentServiceImpl implements DocumentService {
private final MongoDbRepository mongoDbRepository;
private final JpaRepository jpaRepository;
@Autowired
public DocumentServiceImpl(MongoDbRepository mongoDbRepository,JpaRepository jpaRepository) {
this.mongoDbRepository = mongoDbRepository;
this.jpaRepository = jpaRepository;
}
@Override
@Transactional("chainedTransactionManager")
public void insertNewDoc(Map<String,Object> rawData) {
//use org.springframework.transaction.annotation.Transactional so you can define used transactionManager
//jpaRepository.insert...
Document mongoDoc = new Document(rawData);
mongoDbRepository.insertData(mongoDoc)
//you can test like this : breakpoint and throw new IllegalStateException()
//to see that data is not commited
}