Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring数据和mongodb-使用@Transactional中的Spring进行简单回滚_Java_Spring_Hibernate_Mongodb_Rollback - Fatal编程技术网

Java Spring数据和mongodb-使用@Transactional中的Spring进行简单回滚

Java Spring数据和mongodb-使用@Transactional中的Spring进行简单回滚,java,spring,hibernate,mongodb,rollback,Java,Spring,Hibernate,Mongodb,Rollback,我有两个存储库,一个用于mongodb(DocumentRepository),另一个用于hibernate实体(EntityRepository) 我有一个简单的服务: @Transactional public doSomePersisting() { try { this.entityRepository.save(entity); this.documentRepository.save(document); }

我有两个存储库,一个用于mongodb(DocumentRepository),另一个用于hibernate实体(EntityRepository)

我有一个简单的服务:

 @Transactional
 public doSomePersisting() {
     try {
           this.entityRepository.save(entity);
           this.documentRepository.save(document);
     }
     catch(...) {
         //Rollback mongoDB here
     }
 }
是否可以在“//rollback mongoDB here”行上回滚mongoDB?
我已经从实体部分(事务性注释)得到一个回滚。

MongoDB不支持事务(至少不在单个文档的范围之外)。如果你想回滚更改,你需要自己手工完成。如果您在某些情况下确实需要在Mongo中实现您自己的事务,那么有一些参考资料描述了如何在Mongo中实现这些事务。你可以看看


这只是对您可以使用的模式的解释。如果您发现在应用程序中绝对需要事务,则应该考虑MunGDB是否适合您的需要。

< P>对不起,请回答我的问题。

早期的代码允许将数据插入MongoDB,甚至在将数据插入PostgreSQL时抛出查询异常(使用myBatis)

我已经解决了MongoDB和关系数据库之间的数据事务问题,@Transactional通过在上述代码中进行这些更改而完美地工作

@Transactional管理解决方案。 Mongo配置类 用于数据插入的服务类 POM.XML

4.0.0
com.abcpluds.sample.mongoapi
mongo api示例
1.0-快照
SpringBootMongoAPI示例
使用Spring数据Mongo的Spring Boot Mongo演示项目
org.springframework.boot
spring启动程序父级
2.0.1.1发布
UTF-8
1.8
org.springframework.boot
SpringBootStarterWeb
org.springframework.boot
弹簧靴起动器执行器
org.springframework.data
spring数据mongodb
2.1.0.1发布
org.mongodb
mongo java驱动程序
org.springframework.data
spring数据共享
2.1.0.1发布
org.mongodb
mongo java驱动程序
3.8.2
org.mybatis
mybatis泉
1.3.1
org.postgresql
postgresql
42.2.2
org.mybatis.spring.boot
迈巴蒂斯弹簧靴起动器
1.3.2
org.mybatis
mybatis
3.4.5
org.springframework.boot
springbootmaven插件

使用MongoDb 4.0.x可以使用事务。如果使用下面的版本,则必须实现两阶段提交

NB:MongoDb仅允许您在拥有复制集的情况下使用事务。

为了同时使用JPA和MongoDb的事务,您必须使用。这个过程是:

  • 创建Jpa事务管理器
  • 创建MongoDb事务管理器
  • 创建ChainedTransactionManager,它将使用上述两个
我的conf如下所示(我不使用spring boot,但它应该是等效的):

Jpa配置 MongoDb配置 ChainedTransactionManager配置 mongoDb回购协议示例
@服务
公共类MongoDbRepositoryImpl实现MongoDbRepository{
私有静态最终记录器Logger=Logger.getLogger(MongoDbRepositoryImpl.class);
//MongoOperations将处理mongo会话
私人最终运营;
@自动连线
公共MongoDbRepositoryImpl(MongoOperations操作){
这是操作=操作;
}
@凌驾
公共void insertData(文档){
MongoCollection collection=operations.getCollection(“myCollection”);
收藏.插入器(文件);
}
在您的服务中使用事务
@服务
公共类DocumentServiceImpl实现DocumentService{
私有最终Mongodbrespository Mongodbrespository;
私人最终存款;
@自动连线
公共文档服务impl(MongoDbRepository MongoDbRepository,JpaRepository JpaRepository){
this.mongodbepository=mongodbepository;
this.jpaRepository=jpaRepository;
}
@凌驾
@事务(“链接事务管理器”)
公共void insertNewDoc(地图原始数据){
//使用org.springframework.transaction.annotation.Transactional,以便您可以定义使用的transactionManager
//jpaRepository.insert。。。
文件mongoDoc=新文件(原始数据);
mongoDbRepository.insertData(mongoDoc)
//您可以这样测试:断点并抛出新的IllegalStateException()
//查看数据是否未提交
}

MongoDB v4.x.x与@Transactional完美配合,它们通过使用以下依赖项和存储库对此提供了明确的支持:-

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-releasetrain</artifactId>
    <version>Lovelace-M3</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
在这里,我将mongo与kafka一起用作1事务,因此,如果此处发生任何已检查或未检查的异常,则应回滚mongo事务,因此我使用@Transactional(rollboor=exception.class):-

@Transactional(rollboor=Exception.class)
public void receiveInventRequest(TransactionDto TransactionDto)抛出
中断异常{
//数据库插入
TransactionRequest TransactionRequest=requestDbDumpService.dumpToDb(transactionDto);
//卡夫卡插页
ListenableFuture kafkaResult=kafkaTemplate.send(kafkaProducerQueueName,“ID”,transactionDto);
SendResult kafkaSendResult=kafkaResult.get();
}

如果任何人需要
事务性
支持反应性风格spring bootMongoDb集成,那么请仔细阅读答案

您可以将mongo操作留到最后(如示例中所示)。因此,当它失败时,它将回滚之前的spring操作。您通常希望mongo执行原子操作,这样可以保持两个数据源的一致性。
@Service
@Component
public class TestRepositoryImpl implements TestRepository{
    private static final Logger LOG = LoggerFactory.getLogger(TestRepositoryImpl.class);


@Autowired MongoConfig mongoConfig;
@Autowired MongoTemplate mongoTemplate;
@Autowired MongoTransactionManager mongoTransactionManager;

@Autowired UserService userService;

@Override
@Transactional
public void save(Test test){
    int projectId = 100;
    if (projectId != 0) {
        mongoTemplate = mongoConfig.fetchMongoTemplate(100);
        mongoTemplate.setSessionSynchronization(SessionSynchronization.ALWAYS);
    }
    mongoTemplate.insert(test);
    IdName idName = new IdName();
    idName.setName("test");
    mongoTemplate.insert(idName);
    User user = new User();
    user.setName("Demo");
    user.setEmail("srini@abspl.in");
    user.setPassword("sdfsdfsdf");
    userService.save(user);
    }
 }
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.abcplusd.sample.mongoapi</groupId>
  <artifactId>sample-mongo-api</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>Sample Spring Boot Mongo API</name>
  <description>Demo project for Spring Boot Mongo with Spring Data Mongo</description>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-mongodb</artifactId>
      <version>2.1.0.RELEASE</version>
      <exclusions>
        <exclusion>
          <groupId>org.mongodb</groupId>
          <artifactId>mongo-java-driver</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-commons</artifactId>
      <version>2.1.0.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.mongodb</groupId>
      <artifactId>mongo-java-driver</artifactId>
      <version>3.8.2</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.2.2</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>1.3.2</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.5</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>
@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;
    }
}
@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);
    }
}
@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;
    }

}
@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 
    }
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-releasetrain</artifactId>
    <version>Lovelace-M3</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.MongoTransactionManager;
import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;

@Configuration
@EnableMongoRepositories(basePackages = "com.airtel.africa.caxr.repository")
public class MongoTransactionConfig extends AbstractMongoClientConfiguration {

    @Value("${spring.data.mongodb.host}")
    private String host;
    @Value("${spring.data.mongodb.port}")
    private String port;
    @Value("${spring.data.mongodb.database}")
    private String database;

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

    @Override
    protected String getDatabaseName() {
        return database;
    }
    @Override
    public MongoClient mongoClient() {
        String connectionString = "mongodb://"+host+":"+port;

        return MongoClients.create(MongoClientSettings.builder()
            .applyConnectionString(new 
        ConnectionString(connectionString)).build());
    }
}
@Transactional(rollbackFor = Exception.class)
public void receiveInEventRequest(TransactionDto transactionDto) throws 
    InterruptedException, ExecutionException {
    // db insert    
    TransactionRequest transactionRequest = requestDbDumpService.dumpToDb(transactionDto);
    // kafka insert
    ListenableFuture<SendResult<String, TransactionDto>> kafkaResult = kafkaTemplate.send(kafkaProducerQueueName, “ID”, transactionDto);
    SendResult<String, TransactionDto> kafkaSendResult = kafkaResult.get();
}