복붙노트

[SPRING] Spring 데이터와 mongodb - @Transactional 내에서 스프링으로 간단한 롤백

SPRING

Spring 데이터와 mongodb - @Transactional 내에서 스프링으로 간단한 롤백

나는 mongodb (DocumentRepository)와 Hibernate 엔티티 (EntityRepository)를위한 2 개의 저장소를 가지고있다.

나는 간단한 서비스를 가지고있다 :

 @Transactional
 public doSomePersisting() {
     try {
           this.entityRepository.save(entity);
           this.documentRepository.save(document);
     }
     catch(...) {
         //Rollback mongoDB here
     }
 }

mongoDB를 "// Rollback mongoDB here"라인에서 롤백 할 수 있습니까? 이미 엔티티 부분 (트랜잭션 주석)에서 롤백을 얻었습니다.

해결법

  1. ==============================

    1.MongoDB는 트랜잭션을 지원하지 않습니다 (적어도 단일 문서의 범위를 벗어나지는 않음). 변경 사항을 롤백하려면 직접 수정해야합니다. Mongo에서 자신의 거래를 구현하는 방법을 설명하는 몇 가지 리소스가 있습니다. 당신은 ..

    MongoDB는 트랜잭션을 지원하지 않습니다 (적어도 단일 문서의 범위를 벗어나지는 않음). 변경 사항을 롤백하려면 직접 수정해야합니다. Mongo에서 자신의 거래를 구현하는 방법을 설명하는 몇 가지 리소스가 있습니다. 당신은 ..

    http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits/

    이것은 사용할 수있는 패턴에 대한 설명 일뿐입니다. 응용 프로그램에서 트랜잭션이 절대적으로 필요하다고 판단되면 MongoDB가 사용자의 요구에 적합한 지 여부를 고려해야합니다.

  2. ==============================

    2.내 대답을 다시 보내 주셔서 죄송합니다.

    내 대답을 다시 보내 주셔서 죄송합니다.

    앞의 코드는 MongoDB에 데이터를 삽입 할 수있었습니다. 심지어 쿼리 예외 (PostgreSQL에 데이터를 삽입 할 때 myBatis 사용)도 던졌습니다.

    MongoDB와 관계형 데이터베이스 사이의 데이터 트랜잭션 문제를 해결했으며 @Transactional은 위의 코드에서 이러한 변경을 통해 완벽하게 작동합니다.

    @Configuration
    public class MongoConfig extends AbstractMongoConfiguration{
        private static final Logger LOG = LoggerFactory.getLogger(MongoConfig.class);
    
        @Value("${spring.data.mongodb.database}")
        private String dbName;
    
        @Value("${spring.data.mongodb.host}")
        private String dbHost;
    
        @Value("${spring.data.mongodb.port}")
        private int dbPort;
    
        @Override
        public String getDatabaseName() {
            return dbName;
        }
    
        @Bean
        public MongoClient mongoClient(){
            return new MongoClient(dbHost, dbPort);
        }
    
        @Bean
        public MongoDbFactory mongoDbFactory(){
            return new SimpleMongoDbFactory(mongoClient(),dbName);
        }
    
        @Bean
        public MongoTemplate mongoTemplate() {
            DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
            MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
            // Don't save _class to mongo
            mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
            MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(),mappingMongoConverter);
            mongoTemplate.setSessionSynchronization(SessionSynchronization.ON_ACTUAL_TRANSACTION);
            return mongoTemplate;
        }
    
        public MongoTemplate fetchMongoTemplate(int projectId) {
            DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
            MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
            // Don't save _class to mongo
            mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
            MongoDbFactory customizedDBFactory = new SimpleMongoDbFactory(mongoClient(), dbName+"_"+projectId);
            MongoTemplate mongoTemplate = new MongoTemplate(customizedDBFactory,mappingMongoConverter);
            MongoTransactionManager mongoTransactionManager = new MongoTransactionManager(customizedDBFactory);
            return mongoTemplate;
        }
    
        @Bean
        public MongoTransactionManager mongoTransactionManager() {
            return new MongoTransactionManager(mongoDbFactory());
        }
    
    }
    
    @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>
    
  3. ==============================

    3.MongoDB 롤백은 @Transactional 및 MongoTransactionManager에서 작동하지 않습니다. 전체 코드 구현은 여기에 있습니다.

    MongoDB 롤백은 @Transactional 및 MongoTransactionManager에서 작동하지 않습니다. 전체 코드 구현은 여기에 있습니다.

    @Configuration
    public class MongoConfig extends AbstractMongoConfiguration{
        private static final Logger LOG = LoggerFactory.getLogger(MongoConfig.class);
    
        @Value("${spring.data.mongodb.database}")
        private String dbName;
    
        @Value("${spring.data.mongodb.host}")
        private String dbHost;
    
        @Value("${spring.data.mongodb.port}")
        private int dbPort;
    
        @Override
        public String getDatabaseName() {
            return dbName;
        }
    
        @Bean
        public MongoClient mongoClient(){
            return new MongoClient(dbHost, dbPort);
        }
    
        @Bean
        public MongoDbFactory mongoDbFactory(){
            return new SimpleMongoDbFactory(mongoClient(),dbName);
        }
    
        @Bean
        public MongoTemplate mongoTemplate() {
            DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
            MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
            // Don't save _class to mongo
            mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
            MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(),mappingMongoConverter);
            return mongoTemplate;
        }
    
        public MongoTemplate fetchMongoTemplate(int projectId) {
            DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
            MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
            // Don't save _class to mongo
            mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
            MongoTemplate mongoTemplate = new MongoTemplate(new SimpleMongoDbFactory(mongoClient(), dbName+"_"+projectId),mappingMongoConverter);
            return mongoTemplate;
        }
    
        @Bean
        public MongoTransactionManager mongoTransactionManager() {
            return new MongoTransactionManager(mongoDbFactory());
        }
    }
    
    @Service
    @Component
    public class TestRepositoryImpl implements TestRepository{
        private static final Logger LOG = LoggerFactory.getLogger(TestRepositoryImpl.class);
    
        @Autowired MongoTemplate mongoTemplate;
        @Autowired MongoConfig mongoConfig;
        //@Autowired MongoClient mongoClient;
    
        @Autowired UserService userService;
    
        @Override
        @Transactional
        public void save(Test test){
            LOG.info("mongoTemplate <{}>", mongoTemplate.getDb().getName());
            int projectId = 100;
            if (projectId != 0) {
                mongoTemplate = mongoConfig.fetchMongoTemplate(100);
                LOG.info("mongoTemplate <{}>", mongoTemplate.getDb().getName());
            }
            //Inserting data to mongodb
            mongoTemplate.insert(test);
            IdName idName = new IdName();
            idName.setName("test");
            mongoTemplate.insert(idName);
            //Inserting data to postgreSQL
            User user = new User();
            user.setName("Demo");
            user.setEmail("XXXX@XXXX.in");
            user.setPassword("sdfsdfsdf");
            userService.save(user); //This line throws query exception.
        }
    

    mongodb에서이 줄에서 예외를 던져도 데이터가 롤백되지 않습니다.  userService.save (user); //이 줄은 삽입 쿼리 예외에서 잘못된 구문을 throw합니다.

    ### SQL: insert into test.user(id,name,email,password     values(?,?,?,?)
    ### Cause: org.postgresql.util.PSQLException: ERROR: syntax error at or near "values"
      Position: 50
    ; bad SQL grammar []; nested exception is org.postgresql.util.PSQLException: ERROR: syntax error at or near "values"
      Position: 50] with root cause
    
  4. from https://stackoverflow.com/questions/21386449/spring-data-and-mongodb-simple-roll-back-with-spring-within-transactional by cc-by-sa and MIT license