복붙노트

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

SPRING

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

최신 spring-data-mongodb (1.1.0.M2)와 최신 Mongo Driver (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은 여러 데이터베이스를 쉽게 사용할 수있는 방법이 아닙니다. Mongo와의 연결을 설정하는 가장 좋은 방법은 AbstractMongoConfiguration 클래스를 확장하는 것입니다.

다음 방법을 재정의 한 것을 볼 수 있습니다 :

getDatabaseName()

따라서 하나의 데이터베이스 이름을 사용해야합니다. 그런 다음 저장소 인터페이스는 SimpleMongoRepository 클래스에 전달 된 MongoTemplate 내부에 해당 데이터베이스 이름을 사용합니다.

어디에서 여러 데이터베이스 이름을 사용해야합니까? 여러 데이터베이스 이름, 여러 MongoTempates (데이터베이스 이름 당 하나) 및 여러 다른 구성 클래스를 만들어야합니다. 그리고 저의 저장소 인터페이스가 올바른 템플릿을 사용하지 못합니다. 누군가 그런 시도를하면 알려주세요. 알아 내면 대답을 게시 할 것입니다.

감사.

해결법

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

    1.다음은 내가 생각하는 기사에 대한 링크입니다. http://michaelbarnesjr.wordpress.com/2012/01/19/spring-data-mongo/

    다음은 내가 생각하는 기사에 대한 링크입니다. 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에 리포지토리가 어디에 있는지 알려 주어야합니다. 그들은 모두 같은 디렉토리에 있어야합니다. 서로 다른 하위 디렉토리에 넣으려고했는데 제대로 작동하지 않았습니다. 그래서 그들은 모두 저장소 디렉토리에 있습니다.

    <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> {
    
    }
    

    private 변수 imageRepository의 이름은 콜렉션입니다! Image.java는 imagedb 데이터베이스 내의 이미지 콜렉션에 저장됩니다.

    다음은 레코드를 찾고, 삽입하고, 삭제하는 방법입니다.

    @Service
    public class ImageService {
    
        @Autowired
        private ImageRepository imageRepository;
    }
    

    Autowiring을 사용하면 구성에서 변수 이름을 이름 (id)과 일치시킵니다.

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

    2.SimpleMongoDbFactory를 하위 클래스로 만들고 getDb에서 반환 된 기본 DB가 반환되는 방식을 전략화 할 수 있습니다. 하나의 옵션은 스레드 로컬 변수를 사용하여 여러 MongoTemplate을 사용하는 대신 사용할 Db를 결정하는 것입니다.

    SimpleMongoDbFactory를 하위 클래스로 만들고 getDb에서 반환 된 기본 DB가 반환되는 방식을 전략화 할 수 있습니다. 하나의 옵션은 스레드 로컬 변수를 사용하여 여러 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);
        }
    }
    

    그런 다음 AbstractMongoConfiguration에서 확장하는 @Configuration 클래스의 mongoDBFactory ()를 다음과 같이 재정의하십시오.

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

    클라이언트 코드 (아마도 ServletFilter 또는 일부)에서 다음을 호출해야합니다. ThreadLocalDBNameMongoRepository.setDefaultNameForCurrentThread () Mongo 작업을하기 전에 다음과 같이 다시 설정하십시오. ThreadLocalDBNameMongoRepository.clearDefaultNameForCurrentThread () 너 끝나면.

  3. ==============================

    3.많은 연구와 실험을 거쳐 현재 스프링 데이터 - 몽고 프로젝트가 아직 가능하지 않다고 결론을 내 렸습니다. 위의 baja 방법을 시도하고 특정 장애물을 만났습니다. MongoTemplate은 생성자 내에서 ensureIndexes () 메서드를 실행합니다. 이 메소드는 데이터베이스를 호출하여 주석이 달린 색인이 데이터베이스에 있는지 확인합니다. Spring이 시작될 때 MongoTemplate의 생성자가 호출되어 ThreadLocal 변수를 설정할 기회조차 없다. Spring이 시작할 때 기본값을 이미 설정해야합니다. 요청이 들어올 때 변경해야합니다. 기본 데이터베이스가 없기 때문에 허용되지 않습니다.

    많은 연구와 실험을 거쳐 현재 스프링 데이터 - 몽고 프로젝트가 아직 가능하지 않다고 결론을 내 렸습니다. 위의 baja 방법을 시도하고 특정 장애물을 만났습니다. MongoTemplate은 생성자 내에서 ensureIndexes () 메서드를 실행합니다. 이 메소드는 데이터베이스를 호출하여 주석이 달린 색인이 데이터베이스에 있는지 확인합니다. Spring이 시작될 때 MongoTemplate의 생성자가 호출되어 ThreadLocal 변수를 설정할 기회조차 없다. Spring이 시작할 때 기본값을 이미 설정해야합니다. 요청이 들어올 때 변경해야합니다. 기본 데이터베이스가 없기 때문에 허용되지 않습니다.

    모두는 분실되지 않았다. 우리의 원래 계획은 각 클라이언트를 MongoDB 서버의 자체 MongoDB 데이터베이스를 가리키는 자체 응용 프로그램 서버에서 실행하는 것이 었습니다. 그런 다음 -Dprovider = 시스템 변수를 제공 할 수 있으며 각 서버는 하나의 데이터베이스만을 가리키며 실행됩니다.

    우리는 멀티 테넌트 (multi-tenant) 애플리케이션을 갖도록 지시 받았다. 따라서 ThreadLocal 변수를 시도했다. 그러나 작동하지 않았기 때문에 원래 디자인 한 방식으로 응용 프로그램을 실행할 수있었습니다.

    나는 이것이 모든 일을하도록하는 방법이 있다고 믿습니다. 단지 다른 게시물들에 묘사 된 것 이상을 필요로합니다. 자신 만의 RepositoryFactoryBean을 만들어야합니다. 다음은 스프링 데이터 MongoDB 참조 문서의 예제입니다. 자신 만의 MongoTemplate을 구현하고 ensureIndexes () 호출을 지연 시키거나 제거해야합니다. 하지만 MongoTemplate이 Spring 대신 호출되도록하려면 몇 개의 클래스를 다시 작성해야합니다. 즉, 많은 작업. 내가보고 싶은 일이나 일을하는 것, 시간이 없다.

    답변 주셔서 감사합니다.

  4. ==============================

    4.살펴볼 지점은 MongoDbFactory 인터페이스입니다. 기본 구현은 Mongo 인스턴스를 사용하며 모든 응용 프로그램 수명 동안 작동합니다. 스레드 당 (따라서 요청 당) 데이터베이스 사용을 달성하려면 아마도 AbstractRoutingDataSource의 라인을 따라 무언가를 구현해야 할 것입니다. 아이디어는 꽤 많이 당신이 호출 (ThreadLocal 내가 추측 바인딩) 당 세입자를 찾아야 할 템플릿 메서드를 가지고 사전에 정의 된 것들 또는 사용자 정의 논리의 집합에서 신선한 하나와 함께 나오기 위해 Mongo 인스턴스를 선택하십시오 새로운 세입자 등

    살펴볼 지점은 MongoDbFactory 인터페이스입니다. 기본 구현은 Mongo 인스턴스를 사용하며 모든 응용 프로그램 수명 동안 작동합니다. 스레드 당 (따라서 요청 당) 데이터베이스 사용을 달성하려면 아마도 AbstractRoutingDataSource의 라인을 따라 무언가를 구현해야 할 것입니다. 아이디어는 꽤 많이 당신이 호출 (ThreadLocal 내가 추측 바인딩) 당 세입자를 찾아야 할 템플릿 메서드를 가지고 사전에 정의 된 것들 또는 사용자 정의 논리의 집합에서 신선한 하나와 함께 나오기 위해 Mongo 인스턴스를 선택하십시오 새로운 세입자 등

    MongoDbFactory는 일반적으로 getDb () 메소드를 통해 사용됩니다. 그러나 MongoDB에는 getDb (문자열 이름)를 제공해야하는 기능이 있습니다. 관계형 세계의 외래 키와 같은 DBRefs는 완전히 다른 데이터베이스를 문서로 가리킬 수 있습니다. 따라서 위임을 수행하는 경우 해당 기능을 사용하지 마십시오 (다른 DB를 가리키는 DBRef가 getDb (name)을 호출하는 유일한 곳)이거나 명시 적으로 처리하는 것입니다.

    구성의 관점에서 mongoDbFactory ()를 간단히 오버라이드하거나 기본 클래스를 전혀 확장하지 않고 자신 만의 Java 기반 구성을 만들 수 있습니다.

  5. ==============================

    5.내가 다른 DB를 사용하여 자바 구성을 사용하여, 내가 어떻게 그랬 :

    내가 다른 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());    
    }
    

    그래서 내가 데이터베이스를 변경할 필요가있는 경우에만 사용할 구성을 선택하십시오.

  6. ==============================

    6.내가 아는 한, 현재 db를 변경하는 데있어 더 많은 유연성을 원합니다.

    내가 아는 한, 현재 db를 변경하는 데있어 더 많은 유연성을 원합니다.

    다중 소유권을 구현하는 프로젝트를 간단한 방법으로 연결했습니다.

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

    그것은 SimpleMongoDbFactory를 구현하고 특정 순간에 사용할 올바른 db를 해결하기 위해 사용자 정의 getDB 메소드를 제공합니다. 예를 들어 Redis에서 캐시 할 수있는 SpringSession 객체의 HttpSession에서 db 세부 정보를 검색하는 등 다양한 방법으로 향상시킬 수 있습니다.

    동시에 다른 dbs를 사용하는 다른 mongoTemplates를 가지려면 어쩌면 mongoDbFactory의 범위를 세션으로 변경할 수 있습니다.

    참고 문헌 :

    다중 거주자 - 봄 - 몽고

  7. from https://stackoverflow.com/questions/12078669/spring-data-mongodb-connect-to-multiple-databases-in-one-mongo-instance by cc-by-sa and MIT license