Spring使用Mongo实现JPA

时间:2016-10-04 11:39:52

标签: java spring spring-data-jpa spring-data-mongodb

我是Spring Framework的新手,并且在设置我正在进行的项目时遇到了一些麻烦。我需要能够连接到两个不同的数据库,一个是MongoDB,另一个是MSSQL。我正在使用JPA连接到MSSQL。

我遇到的问题是,当我希望它调用MSSQL时,它似乎试图调用Mongo数据库,我不确定如何告诉它要读什么。我已经看到帖子建议使用@Qualifier注释将其指向正确的实现,但我不认为这对我的情况有用。

@RestController
@RequestMapping("/software")
public class SoftwareEndpoint {



    @Autowired
    SoftwareRepository repo;    


    /**********************************************************************************
    ********************************MSSQL calls****************************************
    ***********************************************************************************/
    @RequestMapping(value="/all",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON)
    String getAllSoftware(){

        System.out.println("Here1");
        List<Software> allSoftware = (List<Software>) repo.findAll();
        System.out.println("Here2");
        //rest of method and class

上面显示了我的控制器类的片段,其中包含我的SoftwareRepository实例。我也会在db调用之前和之后打印到out stream。

出流只显示“Here1”,继续打印出这一行:

2016-10-04 07:35:39.810  INFO 4236 --- [nio-8080-exec-2] org.mongodb.driver.cluster               : No server chosen by ReadPreferenceServerSelector{readPreference=primary} from cluster description ClusterDescription{type=UNKNOWN, connectionMode=SINGLE, all=[ServerDescription{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Connection refused: connect}}]}. Waiting for 30000 ms before timing out

然后在超时时抛出异常。

我没有在本地运行的mongo实例,但是会有应用程序部署的位置,但我不相信这是问题,因为在点击该端点时,它不应该进行调用到Mongo数据库,应该尝试联系MSSQL。

TLDR:如何指定Spring用于特定存储库或数据库调用的数据库实现?

2 个答案:

答案 0 :(得分:1)

您可以根据上下文中的配置在spring中连接到不同的数据库。

以下代码用于连接MySql和Mongo DB。你可以用MySQL替换MySql,前提是你有JDBC。检查http://jdbforms.sourceforge.net/UsersGuide/html/ch20s02.html,了解JDBC连接的属性是什么意思。

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg ref="mySqldataSource" /> <!-- Change the datasource to MSSQL-->
    </bean>

    <bean id="mySqldataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="removeAbandoned">
            <value>true</value>
        </property>
        <property name="removeAbandonedTimeout">
            <value>30</value>
        </property>
        <property name="driverClassName">
            <value>MSSQL_DRIVER_CLASS_NAME</value>
        </property>
        <property name="url">
            <value>MSSQL_DATABASE_URL</value>
        </property>
        <property name="username">
            <value>MSSQL_DB_USER_NAME</value>
        </property>
        <property name="password">
            <value>MSSQL_DB_PASSWORD</value>
        </property>
        <property name="maxIdle"> 
            <value>10</value>
        </property>
        <property name="maxActive"> 
            <value>10</value>
        </property>
        <property name="maxWait">
            <value>100000</value>
        </property>
        <property name="testOnBorrow">
            <value>false</value>
        </property>
        <property name="testWhileIdle">
            <value>false</value>
        </property>
        <property name="timeBetweenEvictionRunsMillis">
            <value>60000</value>
        </property>
        <property name="minEvictableIdleTimeMillis">
            <value>60000</value>
        </property>
        <property name="numTestsPerEvictionRun">
            <value>1</value>
        </property>
        <property name="defaultTransactionIsolation" value="1" />
        <property name="poolPreparedStatements" value="true" />
        <property name="maxOpenPreparedStatements" value="1" />
    </bean>

    <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"></bean>

以下是连接到mongodb

    <mongo:db-factory dbname="mongoDbName" host="mongoServer" port="mongoPort"/>


    <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
    </bean>
    <mongo:repositories base-package="com.test.repoPackage"/> <!-- Package containing the mongo repository interfaces -->

现在您可以使用spring提供的存储库。

编辑1:假设配置名称为springConfig.properties。在mongo:db-factory中属性dbname,host和port的上面示例中,您希望在springConfig.properties中配置值。所以我们在下面命名:

mongoServer = xxx.xx.xxx.xxx
mongoPort = 27017
mongoDb = testDb

现在需要修改上下文文件以导入springConfig.properties。这在上下文文件中完成:

<bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
        <property name="locations" >
            <list>              
                <value>classpath:/log4j.properties</value>
                <value>classpath:/springConfig.properties</value>
            </list>
        </property>
    </bean>

bean mongo:db-factory现在看起来像:

<mongo:db-factory dbname="${mongoDb}" host="${mongoServer}" port="${mongoPort}"/>

请注意,config(dbname,host和port)中的“keys”表示为$ {}。这将替换为配置中的键值。

答案 1 :(得分:0)

您需要为JPA分配两个独立的配置。不要忘记禁用JPA自动配置。

@SpringBootApplication(
        exclude={
           DataSourceAutoConfiguration.class,
           DataSourceTransactionManagerAutoConfiguration.class,
           HibernateJpaAutoConfiguration.class
        }
)

下面是两个不同的sql数据库的示例。可以很容易地适应您的需求(当第二个数据源是mongo时)。

第一个:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "sellitEntityManagerFactory",
        transactionManagerRef = "sellitTransactionManager",
        basePackages = { "co.sellit.core.api.repository.sellit" }
)
public class JpaSellitConfig {

    @Bean
    @ConfigurationProperties(prefix="spring.datasource.sellit")
    public DataSourceProperties sellitDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @ConfigurationProperties(prefix="spring.hikaricp.sellit")
    public HikariConfig sellitHikariConfig() {
        HikariConfig hikariConfig = new HikariConfig();
        return hikariConfig;
    }

    @Bean
    public DataSource sellitDataSource(
            @Qualifier("sellitHikariConfig") HikariConfig sellitHikariConfig,
            @Qualifier("sellitDataSourceProperties") DataSourceProperties sellitDataSourceProperties) {

        sellitHikariConfig.setDriverClassName(sellitDataSourceProperties.getDriverClassName());
        sellitHikariConfig.setJdbcUrl(sellitDataSourceProperties.getUrl());
        sellitHikariConfig.setUsername(sellitDataSourceProperties.getUsername());
        sellitHikariConfig.setPassword(sellitDataSourceProperties.getPassword());
        sellitHikariConfig.setConnectionTestQuery("SELECT 1");

        HikariDataSource hikariDataSource = new HikariDataSource(sellitHikariConfig);
        return hikariDataSource;
    }

    @Bean
    @ConfigurationProperties(prefix="spring.jpa.sellit")
    public JpaVendorAdapter sellitJpaVendorAdapter() {
        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        return jpaVendorAdapter;
    }

    @Bean
    @Autowired
    public EntityManagerFactory sellitEntityManagerFactory(
            @Qualifier("sellitDataSource") DataSource sellitDataSource,
            @Qualifier("sellitJpaVendorAdapter") JpaVendorAdapter sellitJpaVendorAdapter) {

        LocalContainerEntityManagerFactoryBean lemf = new LocalContainerEntityManagerFactoryBean();
        lemf.setDataSource(sellitDataSource);
        lemf.setJpaVendorAdapter(sellitJpaVendorAdapter);
        lemf.setPackagesToScan("co.sellit.core.api.entity.sellit");
        lemf.setPersistenceUnitName("sellitPersistenceUnit");
        lemf.afterPropertiesSet();
        return lemf.getObject();
    }

    @Bean
    @Autowired
    public EntityManager sellitDataSourceEntityManager(
            @Qualifier("sellitEntityManagerFactory") EntityManagerFactory sellitEntityManagerFactory) {

        return sellitEntityManagerFactory.createEntityManager();
    }

    @Bean
    @Autowired
    @Qualifier("sellitTransactionManager")
    public PlatformTransactionManager sellitTransactionManager(
            @Qualifier("sellitEntityManagerFactory") EntityManagerFactory sellitEntityManagerFactory) {

        return new JpaTransactionManager(sellitEntityManagerFactory);
    }
}

第二个:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
       entityManagerFactoryRef = "ofEntityManagerFactory",
       transactionManagerRef = "ofTransactionManager",
       basePackages = { "co.sellit.core.api.repository.openfire" }
)
public class JpaOpenfireConfig {

   @Bean
   @ConfigurationProperties(prefix="spring.datasource.openfire")
   public DataSourceProperties ofDataSourceProperties() {
       return new DataSourceProperties();
   }

   @Bean
   @ConfigurationProperties(prefix="spring.hikaricp.openfire")
   public HikariConfig ofHikariConfig() {
       HikariConfig hikariConfig = new HikariConfig();
       return hikariConfig;
   }

   @Bean
   public DataSource ofDataSource(
           @Qualifier("ofHikariConfig") HikariConfig ofHikariConfig,
           @Qualifier("ofDataSourceProperties") DataSourceProperties ofDataSourceProperties) {

       ofHikariConfig.setDriverClassName(ofDataSourceProperties.getDriverClassName());
       ofHikariConfig.setJdbcUrl(ofDataSourceProperties.getUrl());
       ofHikariConfig.setUsername(ofDataSourceProperties.getUsername());
       ofHikariConfig.setPassword(ofDataSourceProperties.getPassword());
       ofHikariConfig.setConnectionTestQuery("SELECT 1");

       HikariDataSource hikariDataSource = new HikariDataSource(ofHikariConfig);
       return hikariDataSource;
   }

   @Bean
   @ConfigurationProperties(prefix="spring.jpa.openfire")
   public JpaVendorAdapter ofJpaVendorAdapter() {
       HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
       return jpaVendorAdapter;
   }

   @Bean
   @Autowired
   public EntityManagerFactory ofEntityManagerFactory(
           @Qualifier("ofDataSource") DataSource ofDataSource,
           @Qualifier("ofJpaVendorAdapter") JpaVendorAdapter ofJpaVendorAdapter) {

       LocalContainerEntityManagerFactoryBean lemf = new LocalContainerEntityManagerFactoryBean();
       lemf.setDataSource(ofDataSource);
       lemf.setJpaVendorAdapter(ofJpaVendorAdapter);
       lemf.setPackagesToScan("co.sellit.core.api.entity.openfire");
       lemf.setPersistenceUnitName("ofPersistenceUnit");
       lemf.afterPropertiesSet();
       return lemf.getObject();
   }

   @Bean
   @Autowired
   public EntityManager ofDataSourceEntityManager(
           @Qualifier("ofEntityManagerFactory") EntityManagerFactory ofEntityManagerFactory) {

       return ofEntityManagerFactory.createEntityManager();
   }

   @Bean
   @Autowired
   @Qualifier("ofTransactionManager")
   public PlatformTransactionManager ofTransactionManager(
           @Qualifier("ofEntityManagerFactory") EntityManagerFactory ofEntityManagerFactory) {

       return new JpaTransactionManager(ofEntityManagerFactory);
   }


}

所以来自包co.sellit.core.api.repository.sellit的存储库将使用sellit db

但是包co.sellit.core.api.repository.openfire中的存储库将使用openfire数据库。

更新(xml配置版本)

<bean id="openfireDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/openfire?characterEncoding=UTF-8" />
</bean>

<bean id="sellitDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/sellit?characterEncoding=UTF-8" />
</bean>

<bean id="openfireSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="openfireDataSource" />
    <property name="packagesToScan" value="co.sellit.core.api.repository.openfire" />
    <property name="hibernateProperties">
        <props>
           ...
        </props>
    </property>
</bean>

<bean id="sellitSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="sellitDataSource" />
    <property name="packagesToScan" value="co.sellit.core.api.repository.sellit" />
    <property name="hibernateProperties">
        <props>
            ...
        </props>
    </property>
</bean>

<bean id="openfireTxnManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="openfireSessionFactory" />
</bean>

<bean id="sellitTxnManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sellitSessionFactory" />
</bean>

<tx:annotation-driven transaction-manager="openfireTxnManager" />
<tx:annotation-driven transaction-manager="sellitTxnManager" />