2013-02-21 6 views
6

Ich habe recherchiert und fand einen explaination and sample code wie Feder JPA mit mehreren Datenquellen Daten zu verwenden, die mehrere JPA zur Konfiguration bezieht: Repositories in der XML-Konfiguration wie folgt:Mehrere jpa: Repositories in XML-Konfiguration, wie mit @EnableJPARepositories mit Spring Java Config zu konfigurieren?

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

Wie würden Sie erklären beide der oben genannten jpa: Repositories-Konfigurationen mit Java-Konfiguration und der Annotation @EnableJpaRepositories?

Die Annotation scheint nur einen Satz von Attributen zu unterstützen (d. H. Nur für ein jpa: Repository) und es ist nicht möglich, die Annotation mehrmals zu deklarieren.

Antwort

0

Sie können versuchen, es auf zwei Klassen (eine @EnableJpaRepositories pro @Configuration) setzen.

17

Ich habe ein 'minimales' Projekt mit mehreren Datenquellen erstellt, um mir zu helfen, das herauszufinden. Es gibt 7 Java-Klassen und andere Konfig darin, deshalb werde ich nur Schlüsselauszüge in dieser Antwort veröffentlichen. Sie können das vollständige Projekt von GitHub erhalten: https://github.com/gratiartis/multids-demo

Die Demo richten zwei JPA-Entitäten:

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

im Zusammenhang mit diesen werden wir zwei Repositories erstellen. Dank der awesomeness von Spring Data können wir uns ein paar ziemlich voll funktions Repositories rein durch die JpaRepository erweitern Definition von Schnittstellen erhalten:

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

Jetzt müssen wir jede dieser Karten auf einem Tisch in seiner eigenen Datenbank sicherzustellen, dass .

Um dies zu erreichen, benötigen wir zwei separate Entity Manager, von denen jeder eine andere Datenquelle hat. In einer Spring-Java-Konfiguration @Configuration können wir jedoch nur eine Annotation haben, und jede solche Annotation kann nur eine EntityManagerFactory referenzieren. Um dies zu erreichen, erstellen wir zwei separate Klassen: FooConfig und BarConfig.

HSQL basierend auf einer eingebetteten Datenbank Jede dieser @Configuration Klassen wird eine Datasource definieren:

@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(); 
} 

Jede Konfiguration eine EntityManagerFactory definieren sollte, wie oben, die ihre eigenen Datasource() @Bean Methode verweist. Es definiert auch einen Pfad zu den @Entity-Beans, die es verwaltet. Sie müssen sicherstellen, dass @Entity-Beans für verschiedene Datenquellen in verschiedenen Paketen enthalten sind.

An dieser Stelle ist es erwähnenswert, dass, wenn jede dieser Konfigurationen die Standardnamen für Schlüsselpersistenz-Beans verwendet (zB entityManagerFactory), Spring zwei Beans mit der EntityManager-Schnittstelle erkennt, die beide den gleichen Namen haben . So wird einer ausgewählt. Dies führt zu Fehlern wie: https://github.com/gratiartis/multids-demo/tree/1-unnamed-entitymanager-beans

Dies liegt daran, in diesem Beispiel hat Frühling die Bohnen im Zusammenhang mit der „foodb verdrahtet:

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

Dies kann in dem Zweig des Demo-Projektes hier zu sehen "Datenbank und Bar ist keine Entität in dieser Datenbank. Leider wurde das BarRepository mit dem Foo Entity Manager verbunden.

Wir lösen dieses Problem, indem wir alle unsere Beans in jeder Konfigurationsklasse benennen. dh

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

An diesem Punkt, wenn Sie die Tests im Projekt auszuführen waren, könnten Sie Warnungen sehen wie:

No bean named 'entityManagerFactory' is defined. 

Dies ist, weil ... ... Trommelwirbel haben wir nicht eine EntityManagerFactory mit dem Standardnamen "entityManagerFactory". Wir haben eine namens "fooEntityManagerFactory" und eine andere "barEntityManagerFactory". Spring sucht nach etwas mit einem Standardnamen, also müssen wir es anweisen, die Dinge anders zu verkabeln.

Wie sich herausstellt, ist dies unglaublich einfach zu tun. Wir müssen nur die richtigen Referenzen in die Annotation @EnableJpaRepositories für jede @Configuration-Klasse einfügen.

@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 { 
    // ... 
} 

Wie Sie jede dieser @EnableJpaRepositories Anmerkungen sehen definiert eine bestimmte EntityManagerFactory und PlatformTransactionManager benannt. Sie geben auch an, welche Repositories mit diesen Beans verdrahtet werden sollen. Im Beispiel habe ich die Repositories in datenbankspezifische Pakete gestellt. Es ist auch möglich, jedes einzelne Repository nach Namen zu definieren, indem Sie includeFilters zur Annotation hinzufügen, aber durch die Trennung der Repositories nach Datenbank glaube ich, dass die Dinge besser lesbar sein sollten.

An dieser Stelle sollten Sie über eine funktionierende Anwendung verfügen, die Spring Data-Repositorys verwendet, um Entitäten in zwei separaten Datenbanken zu verwalten. Fühlen Sie sich frei, das Projekt über den obigen Link zu greifen und führen Sie die Tests durch, um dies zu sehen. Hoffentlich ist diese Antwort nützlich für mehr Leute, da ich eine anständige Menge an Zeit damit verbracht habe, dies so sauber wie möglich mit so wenig Code wie möglich zu tun. Ideen zur Verbesserung der Antwort oder des Demo-Projekts sind willkommen.

Verwandte Themen