programing

Spring-data-mongodb는 하나의 Mongo 인스턴스에서 여러 데이터베이스에 연결합니다.

i4 2023. 7. 5. 20:06
반응형

Spring-data-mongodb는 하나의 Mongo 인스턴스에서 여러 데이터베이스에 연결합니다.

저는 최신 spring-data-mongodb(1.1.0)를 사용하고 있습니다.M2) 및 최신 Mongo 드라이버(2.9.0-RC1).여러 클라이언트가 내 애플리케이션에 연결되어 있으며 각 클라이언트에 동일한 Mongo 서버의 "스킴/데이터베이스"를 제공하려고 합니다.드라이버를 직접 사용하는 경우 이 작업은 그리 어려운 작업이 아닙니다.

Mongo mongo = new Mongo( new DBAddress( "localhost", 127017 ) );

DB client1DB = mongo.getDB( "client1" );
DBCollection client1TTestCollection = client1DB.getCollection( "test" );
long client1TestCollectionCount = client1TTestCollection.count();

DB client2DB = mongo.getDB( "client2" );
DBCollection client2TTestCollection = client2DB.getCollection( "test" );
long client2TestCollectionCount = client2TTestCollection.count();

봐요, 진정하세요.그러나 spring-data-mongodb는 여러 데이터베이스를 쉽게 사용할 수 있는 방법을 허용하지 않습니다. 방설법에 대한 하는 기본 MongoAbstractMongoConfiguration 클래스를 확장합니다.

다음 방법을 재정의하는 것을 확인할 수 있습니다.

getDatabaseName()

따라서 하나의 데이터베이스 이름을 사용해야 합니다. 내부에서 하며 MongoTemplate로 됩니다. MongoTemplate는 MongoTemplate와 동일한 이름으로 구성됩니다.SimpleMongoRepository학생들

데이터베이스 이름을 여러 개 붙이면 대체 어디에 붙일까요?는 데이터베이스 개, 여러 개, 여러 개 만들어야 .MongoTempates(데이터베이스 이름당 하나) 및 기타 여러 구성 클래스.이 경우에도 저장소 인터페이스에서 올바른 템플릿을 사용할 수 없습니다.그런 것을 시도해 본 사람이 있으면 저에게 알려주세요.제가 알아내면 여기에 답을 올리겠습니다.

감사해요.

여기 당신이 찾고 있는 것이 http://michaelbarnesjr.wordpress.com/2012/01/19/spring-data-mongo/ 이라고 생각하는 기사에 대한 링크가 있습니다.

핵심은 여러 개의 템플릿을 제공하는 것입니다.

각 데이터베이스에 대한 템플릿을 구성합니다.

<bean id="vehicleTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg ref="mongoConnection"/>
    <constructor-arg name="databaseName" value="vehicledatabase"/>
</bean>

각 데이터베이스에 대한 템플릿을 구성합니다.

<bean id="imageTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg ref="mongoConnection"/>
        <constructor-arg name="databaseName" value="imagedatabase"/>
</bean>

<bean id="vehicleTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg ref="mongoConnection"/>
    <constructor-arg name="databaseName" value="vehicledatabase"/>
</bean>

이제 Spring에게 저장소가 어디에 있는지 알려주어야 합니다. 그러면 Spring이 저장소를 주입할 수 있습니다.모두 동일한 디렉토리에 있어야 합니다.다른 하위 디렉터리에 두려고 했지만 제대로 작동하지 않았습니다.따라서 이들은 모두 리포지토리 디렉토리에 있습니다.

<mongo:repositories base-package="my.package.repository">
    <mongo:repository id="imageRepository" mongo-template-ref="imageTemplate"/>
    <mongo:repository id="carRepository" mongo-template-ref="vehicleTemplate"/>
    <mongo:repository id="truckRepository" mongo-template-ref="vehicleTemplate"/>
</mongo:repositories>

각 리포지토리는 인터페이스이며 다음과 같이 작성됩니다(예, 비워둘 수 있습니다).

@Repository
public interface ImageRepository extends MongoRepository<Image, String> {

}

@Repository
public interface TruckRepository extends MongoRepository<Truck, String> {

}

변수의 입니다.imageRepository컬렉션입니다!Image.java는 imageb 데이터베이스 내의 이미지 컬렉션에 저장됩니다.

레코드를 찾고 삽입하고 삭제할 수 있는 방법은 다음과 같습니다.

@Service
public class ImageService {

    @Autowired
    private ImageRepository imageRepository;
}

자동 배선을 사용하면 변수 이름을 구성의 이름(ID)과 일치시킬 수 있습니다.

하위 클래스로 분류할 수 있습니다.SimpleMongoDbFactory을 DB의 기본 DB로 .getDb.한 가지 옵션은 여러 MongoTemplate를 사용하는 대신 스레드 로컬 변수를 사용하여 사용할 DB를 결정하는 것입니다.

이와 같은 것:

public class ThreadLocalDbNameMongoDbFactory extends SimpleMongoDbFactory {
    private static final ThreadLocal<String> dbName = new ThreadLocal<String>();
    private final String defaultName; // init in c'tor before calling super

    // omitted constructor for clarity

    public static void setDefaultNameForCurrentThread(String tlName) {
        dbName.set(tlName);
    }
    public static void clearDefaultNameForCurrentThread() {
        dbName.remove();
    }

    public DB getDb() {
        String tlName = dbName.get();
        return super.getDb(tlName != null ? tlName : defaultName);
    }
}

다음, 그다재의정을 재정의합니다.mongoDBFactory()의 신의에@Configuration 클래스된장에서 확장되는 AbstractMongoConfiguration 예:

@Bean
@Override
public MongoDbFactory mongoDbFactory() throws Exception {
  if (getUserCredentials() == null) {
      return new ThreadLocalDbNameMongoDbFactory(mongo(), getDatabaseName());
  } else {
      return new ThreadLocalDbNameMongoDbFactory(mongo(), getDatabaseName(), getUserCredentials());
  }
}

코드다음을 .ThreadLocalDBNameMongoRepository.setDefaultNameForCurrentThread()과 같이합니다. Mongo 작업수전다재사음설다합니정여용하을에행을기하▁before다니재합▁it설▁mong정:▁and여.ThreadLocalDBNameMongoRepository.clearDefaultNameForCurrentThread()당신이 끝난 후에

그래서 많은 연구와 실험 끝에, 저는 이것이 아마도 아직 현재의 것이 아니라는 결론을 내렸습니다.spring-data-mongodb프로트젝. 을 시도해 특정한장애물에 .위에서 baja의 방법을 시도해 보았는데 특정 장애물에 부딪혔습니다.MongoTemplate실행합니다.ensureIndexes()생성자 내부의 메서드입니다.이 메서드는 데이터베이스를 호출하여 주석이 달린 인덱스가 데이터베이스에 있는지 확인합니다.의 :MongoTemplate다음 시간에 호출됩니다.Spring시작하기 때문에 나는 결코 설정할 기회가 없습니다.ThreadLocal변수.다음과 같은 경우 기본값을 이미 설정해야 합니다.Spring시작한 다음 요청이 들어오면 변경합니다.기본 데이터베이스를 원하지 않거나 가지고 있지 않으므로 허용되지 않습니다.

하지만 모든 것이 사라진 것은 아닙니다.우리의 원래 계획은 각 클라이언트가 자체 애플리케이션 서버에서 실행되고 자체 애플리케이션 서버를 가리키도록 하는 것이었습니다.MongoDB에 있는 MongoDB서버.그러면 다음을 제공할 수 있습니다.-Dprovider=시스템 변수 및 각 서버는 하나의 데이터베이스만 가리키며 실행됩니다.

애플리케이션을를 받았기 에 멀티 테넌트(Multi-tenant)를 .ThreadLocal변수. 에, 방식으로 할 수 .하지만 작동하지 않았기 때문에, 우리는 원래 디자인했던 방식으로 애플리케이션을 실행할 수 있었습니다.

저는 이것을 모두 작동시킬 수 있는 방법이 있다고 생각합니다. 다른 게시물에 설명된 것보다 더 많은 것이 필요합니다.당신은 당신 자신의 것을 만들어야 합니다.RepositoryFactoryBean다음은 Spring Data MongoDB Reference Docs의 예입니다.당신은 여전히 당신 자신의 것을 구현해야 할 것입니다.MongoTemplate 합니다.ensureIndexes() 몇 할 수 있을 것입니다. 하지만 당신은 몇 개의 수업을 다시 써야 할 것입니다.MongoTemplate는 대호출다니 에 로 .Spring's다시 말해서, 많은 일을 해야 합니다.제가 일어나거나 하고 싶은 일, 혹은 하고 싶은 일, 저는 단지 시간이 없었습니다.

답변 감사합니다.

살펴봐야 할 지점입니다.MongoDbFactory인터페이스의 기본 구현은 Mongo 인스턴스를 사용하며 모든 애플리케이션 수명 동안 해당 인스턴스와 함께 작동합니다.스레드별(따라서 요청별) 데이터베이스 사용을 달성하려면 AbstractRoutingDataSource와 같은 방법을 구현해야 합니다.즉, 호출당 테넌트를 조회해야 하는 템플릿 방법이 있다는 것입니다.ThreadLocal를 선택한 "바운드"를 합니다.Mongo미리 정의된 논리 집합 또는 일부 사용자 지정 논리에서 인스턴스를 생성하여 새 테넌트 등에 대한 새로운 논리를 생성합니다.

을 명심하세요.MongoDbFactoryget는 을 통해 됩니다.getDb()에는 MongoDB.getDb(String name).DBRefs(관계 세계에서 외부 키와 같은)는 완전히 다른 데이터베이스를 문서를 가리킬 수 있습니다.따라서 위임을 수행하는 경우 해당 기능을 사용하지 마십시오(제 생각에는DBRef은 다를 DB 가유일한호출위다치니입리는른키▁calling▁places▁only다▁the를 부르는 유일한 장소입니다.getDb(name) 또는 명시적으로 처리합니다.

볼 때 " " " " " " " " " " " " " " " " " " " " " " " " " " " 를 덮어쓸 수 .mongoDbFactory()완전히 또는 단순히 기본 클래스를 확장하지 않고 사용자만의 Java 기반 구성을 만듭니다.

Java Config를 사용하여 다른 DB를 사용했습니다. 이렇게 했습니다.

@Bean 
public MongoDbFactory mongoRestDbFactory() throws Exception { 
    MongoClientURI uri=new MongoClientURI(environment.getProperty("mongo.uri")); 
    return new SimpleMongoDbFactory(uri);
}

@Override
public String getDatabaseName() {
    return "rest";
}

@Override
public @Bean(name = "secondaryMongoTemplate") MongoTemplate mongoTemplate() throws Exception{ //hay que cambiar el nombre de los templates para que el contendor de beans sepa la diferencia  
    return new MongoTemplate(mongoRestDbFactory());    
}

그리고 다른 하나는 다음과 같았습니다.

@Bean 
public MongoDbFactory restDbFactory() throws Exception {
    MongoClientURI uri = new MongoClientURI(environment.getProperty("mongo.urirestaurants")); 
    return new SimpleMongoDbFactory(uri);
}

@Override
public String getDatabaseName() {
    return "rest";
}

@Override
public @Bean(name = "primaryMongoTemplate") MongoTemplate mongoTemplate() throws Exception{ 
    return new MongoTemplate(restDbFactory());    
}

따라서 데이터베이스를 변경해야 할 때 사용할 구성만 선택합니다.

Spring 부트 V2.6.2의 예:

"application.yml" 파일의 내용:

spring:
  application:
    name: myApp
  autoconfigure:
  data:
    mongodb:
      host: localhost
      port: 27017
      database: FirstDatabase
    mongodbreference:
      host: localhost
      port: 27017
      database: SecondDatabase

"MultipleMongoProperties.java"라는 클래스에서:

package your.packagename;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "spring.data")
public class MultipleMongoProperties {

    private MongoProperties mongodb = new MongoProperties();

    private MongoProperties mongodbreference = new MongoProperties();
}

그리고 마지막으로 "MultipleMongoConfig.java" 클래스:

    package your.package;
    
    import com.mongodb.client.MongoClients;
    import lombok.RequiredArgsConstructor;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.autoconfigure.mongo.MongoProperties;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.data.mongodb.MongoDatabaseFactory;
    import org.springframework.data.mongodb.core.MongoTemplate;
    import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
    
    @Configuration
    @RequiredArgsConstructor
    @EnableConfigurationProperties(MultipleMongoProperties.class)
    public class MultipleMongoConfig {
    
        private static final Logger LOG = LoggerFactory.getLogger(Multip

leMongoConfig.class);

    private final MultipleMongoProperties mongoProperties;

    private MongoProperties mongoDestination;

    @Bean("referenceMongoTemplate")
    @Primary
    public MongoTemplate referenceMongoTemplate() {

        return new MongoTemplate(referenceFactory(this.mongoProperties.getMongodbreference()));
    }

    @Bean("destinationMongoTemplate")
    public MongoTemplate destinationMongoTemplate() {
        return new MongoTemplate(destinationFactory(this.mongoProperties.getMongodb()));
    }

    public MongoDatabaseFactory referenceFactory(final MongoProperties mongo) {
        this.setUriToMongoProperties(mongo);

        return new SimpleMongoClientDatabaseFactory(MongoClients.create(mongo.getUri()), mongo.getDatabase());
    }

    public MongoDatabaseFactory destinationFactory(final MongoProperties mongo) {
        this.setUriToMongoProperties(mongo);
        return new SimpleMongoClientDatabaseFactory(MongoClients.create(mongo.getUri()), mongo.getDatabase());
    }

    private void setUriToMongoProperties(MongoProperties mongo) {
        mongo.setUri("mongodb://" + mongo.getUsername() + ":" + String.valueOf(mongo.getPassword()) + "@" + mongo.getHost() + ":" + mongo.getPort() + "/" + mongo.getAuthenticationDatabase());

    }

}

다른 클래스에서는 다음을 구현하기만 하면 됩니다.

package your.package;

import com.mongodb.bulk.BulkWriteResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;

@Component
public class CollectionRepositoryImpl implements CollectionsRepository {

    @Autowired
    @Qualifier("referenceMongoTemplate")
    private MongoTemplate referenceMongoTemplate;

    @Autowired
    @Qualifier("destinationMongoTemplate")
    private MongoTemplate destinationMongoTemplate;
...

내가 알기로는 당신은 현재 db를 즉시 변경하는 데 있어 더 많은 유연성을 원합니다.

나는 멀티 테넌시를 구현하는 프로젝트를 간단한 방법으로 연결했습니다.

응용 프로그램의 시작점으로 사용할 수 있습니다.

SimpleMongoDbFactory를 구현하고 사용자 지정 getDB 메서드를 제공하여 특정 시점에 사용할 올바른 db를 확인합니다.예를 들어 Redis에서 캐시할 수 있는 SpringSession 개체에서 HttpSession에서 db 세부 정보를 검색하여 여러 가지 방법으로 개선할 수 있습니다.

동시에 다른 db를 사용하는 다른 mongoTemplate를 사용하려면 mongoDbFactory의 범위를 세션으로 변경할 수 있습니다.

참조:

멀티 테넌트-스프링-몽고드

언급URL : https://stackoverflow.com/questions/12078669/spring-data-mongodb-connect-to-multiple-databases-in-one-mongo-instance

반응형