2013-02-21 175 views
6

我已经研究并发现了一个explaination and sample code为如何使用多个数据源是指配置多个JPA弹簧数据的JPA:如下XML配置库:多个jpa:XML配置中的存储库,如何使用Spring java config配置@EnableJPARepositories?

<jpa:repositories base-package="org.springframework.data.jpa.repository.sample" 
    entity-manager-factory-ref="entityManagerFactory"> 
    <repository:exclude-filter type="assignable" expression="org.springframework.data.jpa.repository.sample.AuditableUserRepository" /> 
</jpa:repositories> 
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample" 
    entity-manager-factory-ref="entityManagerFactory-2" 
    transaction-manager-ref="transactionManager-2"> 
    <repository:include-filter type="assignable" expression="org.springframework.data.jpa.repository.sample.AuditableUserRepository" /> 
</jpa:repositories> 

如何声明上述两个jpa:使用java配置和@EnableJpaRepositories注释的配置库配置?

注解似乎只支持一组属性(即仅用于一个jpa:存储库),并且不可能多次声明注释。

回答

0

您可以尝试将它放在两个@Configuration类别(每个@Configuration一个@EnableJpaRepositories)。

17

我创建了一个'最小'多个数据源项目来帮助我解决如何做到这一点。这里有7个Java类和其他配置,所以我只会在这个答案中发布关键提取。你可以从GitHub得到充分的项目:https://github.com/gratiartis/multids-demo

演示设置了两个JPA实体:

@Entity public class Foo { /* Constructors, fields and accessors/mutators */ } 
@Entity public class Bar { /* Constructors, fields and accessors/mutators */ } 

结合这些,我们将创建两个资源库。

public interface FooRepository extends JpaRepository<Foo, Long> {} 
public interface BarRepository extends JpaRepository<Bar, Long> {} 

现在,我们需要确保这些映射到表在自己的数据库:由于春季数据迷死,我们可以通过定义扩展JpaRepository接口让自己一些漂亮的全功能库纯粹。

为了实现这一点,我们需要两个独立的实体管理器,每个实体管理器都有不同的数据源。但是,在Spring Java配置@Configuration类中,我们只能有一个@EnableJpaRepositories注释,每个这样的注释只能引用一个EntityManagerFactory。为了达到这个目的,我们创建了两个单独的@Configuration类:FooConfig和BarConfig。

每个@Configuration类将定义基于嵌入式HSQL数据库上一个数据源:

@Bean(name = "fooDataSource") 
public DataSource dataSource() { 
    return new EmbeddedDatabaseBuilder() 
      .setName("foodb").setType(EmbeddedDatabaseType.HSQL).build(); 
} 
@Bean(name = "barDataSource") 
public DataSource dataSource() { 
    return new EmbeddedDatabaseBuilder() 
      .setName("bardb").setType(EmbeddedDatabaseType.HSQL).build(); 
} 

@Bean(name = "barEntityManagerFactory") 
public EntityManagerFactory entityManagerFactory() { 
    LocalContainerEntityManagerFactoryBean lef = 
      new LocalContainerEntityManagerFactoryBean(); 
    lef.setDataSource(dataSource()); 
    lef.setJpaVendorAdapter(jpaVendorAdapter); 
    lef.setPackagesToScan("com.sctrcd.multidsdemo.domain.bar"); 
    lef.setPersistenceUnitName("barPersistenceUnit"); 
    lef.afterPropertiesSet(); 
    return lef.getObject(); 
} 
@Bean(name = "fooEntityManagerFactory") 
public EntityManagerFactory entityManagerFactory() { 
    LocalContainerEntityManagerFactoryBean lef = 
      new LocalContainerEntityManagerFactoryBean(); 
    lef.setDataSource(dataSource()); 
    lef.setJpaVendorAdapter(jpaVendorAdapter); 
    lef.setPackagesToScan("com.sctrcd.multidsdemo.domain.foo"); 
    lef.setPersistenceUnitName("fooPersistenceUnit"); 
    lef.afterPropertiesSet(); 
    return lef.getObject(); 
} 

每个配置应当定义一个EntityManagerFactory的,如上所述,它引用其自己的dataSource()@Bean方法。它还定义了它管理的@Entity bean的路径。您需要确保不同数据源的@Entity bean位于不同的包中。

在这一点上,值得注意的是,如果这些配置中的每一个都使用关键持久性bean(即entityManagerFactory)的默认命名,那么Spring将会看到有两个具有EntityManager接口的bean,它们都具有相同的名称。所以会选择一个。这会导致错误,如:https://github.com/gratiartis/multids-demo/tree/1-unnamed-entitymanager-beans

这是因为在这个例子中,春天已经有线了有关“foodb豆:

Not an managed type: class com.sctrcd.multidsdemo.domain.bar.Bar 

这可以在演示项目这里的分支可以看出“数据库,而Bar不是该数据库中的实体。不幸的是,BarRepository已经与Foo实体管理器连接起来。

我们通过命名每个配置类中的所有bean来解决此问题。即

@Bean(name = "fooDataSource") public DataSource dataSource() { .. } 
@Bean(name = "fooEntityManager") public EntityManager entityManager() { .. } 

在这一点上,如果你要运行该项目的测试中,你可能会看到这样的警示:

No bean named 'entityManagerFactory' is defined. 

这是因为... ...击鼓声,我们没有具有默认名称“entityManagerFactory”的EntityManagerFactory。我们有一个叫做“fooEntityManagerFactory”,另一个叫做“barEntityManagerFactory”。 Spring正在寻找具有默认名称的东西,所以我们需要指示它以不同的方式进行连接。

事实证明,这非常简单。我们只需要在每个@Configuration类的@EnableJpaRepositories注释中放置正确的引用。

@Configuration 
@EnableTransactionManagement 
@EnableJpaRepositories(
     entityManagerFactoryRef = "fooEntityManagerFactory", 
     transactionManagerRef = "fooTransactionManager", 
     basePackages = {"com.sctrcd.multidsdemo.integration.repositories.foo"}) 
public class FooConfig { 
    // ... 
} 

@Configuration 
@EnableTransactionManagement 
@EnableJpaRepositories(
     entityManagerFactoryRef = "barEntityManagerFactory", 
     transactionManagerRef = "barTransactionManager", 
     basePackages = { "com.sctrcd.multidsdemo.integration.repositories.bar" }) 
public class BarConfig { 
    // ... 
} 

正如你可以看到,这些@EnableJpaRepositories注解定义了一个特定的EntityManagerFactory命名和PlatformTransactionManager的。他们还指定哪些存储库应该与这些bean连接。在这个例子中,我已经将这些存储库放在数据库特定的包中。也可以通过名称来定义每个单独的存储库,方法是在注释中添加includeFilters,但通过数据库隔离存储库,我相信事情最终应该更具可读性。

此时,您应该有一个使用Spring Data存储库的工作应用程序来管理两个单独数据库中的实体。随意从上面的链接中抓取项目并运行测试以查看发生的情况。希望这个答案对更多人来说是有用的,因为我花了相当多的时间用尽可能少的代码尽可能干净地做到这一点。欢迎任何关于改进答案或演示项目的想法。

相关问题