Spring Data + JPA具有多个数据源但只有一组存储库 [英] Spring Data + JPA with multiple datasources but only one set of Repositories
问题描述
我今天一直在研究这一组,我开始认为我想做的事情可能不可能,所以我转向你,强大的Stackoverflow,寻求帮助。
I've been researching this a bunch today and I'm starting to think that what I want to do may not be possible, so I am turning to you, o mighty Stackoverflow, for help.
我正在用Java构建一个RESTful服务平台,Spring Data 3.1.2 + JPA作为我的持久层(如记录这里)。我的数据模型对象都是作为扩展Spring JpaRepository接口的接口实现的。我已经将所有内容连接起来并且使用单个数据源工作得很好,如本示例所示(请注意,显示的数据源是Derby,但这仅用于开发目的;在生产中,我们将使用Oracle):
I'm building a RESTful services platform in Java, with Spring Data 3.1.2 + JPA as my persistence layer (as documented here). My data model objects are all implemented as interfaces that extend the Spring JpaRepository interface. I've got everything wired up and working nicely with a single datasource, as shown in this example (note that the datasource shown is Derby, but that's just for development purposes; in production, we'll be using Oracle):
<jpa:repositories base-package="com.my.cool.package.repository"/>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="packagesToScan" value="com.my.cool.package" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
</bean>
<bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="url" value="jdbc:derby:derbyDB" />
<property name="username" value="dev" />
<property name="password" value="notARealPassword" />
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.DerbyTenSevenDialect" />
</bean>
问题是此应用程序需要连接到多个(Oracle)数据库。每个传入请求中包含的凭据将包含一个字段,该字段告知应用程序要转到哪个数据库以满足该请求。每个数据库的模式都是相同的,因此不需要为每个数据库提供单独的存储库接口。
The problem is that this application will need to connect to several (Oracle) databases. The credentials included with each incoming request will contain a field that tells the application which database to go to in order to fulfill that request. The schemas for each database are the same, so there's no need for separate repository interfaces for each database.
经过大量的谷歌搜索后,很明显这是一个常见的场景。即:
After a fair amount of Googling, it's clear that this is a common scenario. To wit:
- multiple databases with Spring Data JPA
- Spring + Hibernate + JPA + multiple databases
- how to setup spring data jpa with multiple datasources
和这是一篇由(前?)Spring开发人员撰写的博客文章,它与手头的主题实际上并不相关,但是有人在评论中提到了这一帖子,作者回复了一些信息:
And here's a blog post by a (former?) Spring developer, which isn't actually relevant to the topic at hand, but someone brings it up in the comments, and the author responds with some info:
似乎正在出现的主题是解决此问题的方法是定义多个EntityManagerFactories,并将每个EntityManagerFactories连接到相应的存储库像这样:
The theme that seems to be emerging is that the way to solve this problem is to define multiple EntityManagerFactories, and to wire each one to the appropriate repositories like so:
<jpa:repositories base-package="com.my.cool.package.repository1" entity-manager-factory-ref="firstEntityManagerFactory" />
<jpa:repositories base-package="com.my.cool.package.repository2" entity-manager-factory-ref="secondEntityManagerFactory" />
但是,正如我所提到的,我希望在所有数据源中重用我的存储库,所以这种方法似乎不会起作用。
However, as I've mentioned, I want to reuse my repository across all of the datasources, so this approach doesn't seem like it would work.
我知道我的代码中没有办法从请求中获取相关的信息,并且使用它来确定要使用的数据源(或EntityManagerFactory)。我正在努力的部分是如何获取该数据源/ EntityManagerFactory的句柄并将其注入我的存储库对象。有什么想法?
I know that there's no way around having logic in my code that takes the relevant piece of information from the request, and uses it to determine which datasource (or EntityManagerFactory) to use. The part I'm struggling with is how to get a handle to that datasource/EntityManagerFactory and "inject" it into my repository objects. Any ideas?
推荐答案
如果你真的使用不同的 DataSource
以多租户方式(基本上将请求分配给 DataSource
并坚持整个请求)你应该看一下 AbstractRoutingDataSource
。它本质上提供了一种方法来保持 Map
的 DataSource
es以及一个回调方法来返回一个键是用于查找最终要使用的 DataSource
。这种方法的实现通常会查找一些线程绑定键并将其返回(或者甚至依次将它映射到 DataSource
映射键)。你只需要确保一些web组件首先将该键绑定到该线程。
If you're really using the different DataSource
es in a multi-tenant kind of way (essentially assigning a request to a DataSource
and sticking with it for the entire request) you should have a look at AbstractRoutingDataSource
. It essentially provides a way to keep a Map
of DataSource
es as well as a callback method to return a key to be used to lookup the DataSource
to be used eventually. The implementation of this method usually looks up some thread bound key and return that (or even maps that onto a DataSource
map key in turn). You just have to make sure some web component binds that key to the thread in the first place.
如果你有这个,你的Spring配置只需设置一个bean你的 AbstractRoutingDataSource
的子类,并将 DataSources
的地图输入其中。您的Spring Data JPA设置保持默认方式。 EntityManagerFactoryBean
引用 AbstractRoutingDataSource
,你有一个< jpa:repositories /> ;
仅元素。
If you have that in place your Spring configuration just sets up a bean for your sub-class of AbstractRoutingDataSource
and pipes the map of DataSources
into it. Your Spring Data JPA setup stays the default way. The EntityManagerFactoryBean
refers to the AbstractRoutingDataSource
and you have a single <jpa:repositories />
element only.
这篇关于Spring Data + JPA具有多个数据源但只有一组存储库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!