Spring Data + JPA具有多个数据源但只有一组存储库 [英] Spring Data + JPA with multiple datasources but only one set of Repositories

查看:123
本文介绍了Spring Data + JPA具有多个数据源但只有一组存储库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我今天一直在研究这一组,我开始认为我想做的事情可能不可能,所以我转向你,强大的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:

http://blog.springsource.org/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/#comment-19883 5

似乎正在出现的主题是解决此问题的方法是定义多个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 DataSourcees 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 DataSourcees 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆