Spring Данные + JPA с несколькими источниками данных, но только один набор репозиториев

Я изучаю эту связку сегодня, и я начинаю думать, что то, что я хочу сделать, может быть невозможно, поэтому я обращаюсь к вам, о могучий Stackoverflow, за помощью.

Я создаю платформу сервисов RESTful на Java, Spring Data 3.1.2 + JPA как мой уровень сохранения (как описано здесь). Мои объекты модели данных реализованы как интерфейсы, расширяющие интерфейс Spring JpaRepository. У меня все подключено и хорошо работает с одним источником данных, как показано в этом примере (обратите внимание, что показанный источник данных - Derby, но это только для целей разработки, в производстве мы будем использовать 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) базам данных. Учетные данные, включенные в каждый входящий запрос, будут содержать поле, которое сообщает приложению, к какой базе данных перейти, чтобы выполнить этот запрос. Схемы для каждой базы данных одинаковы, поэтому нет необходимости в отдельных интерфейсах репозитория для каждой базы данных.

После справедливого количества Google, ясно, что это общий сценарий. К остроумию:

А вот сообщение в блоге (бывший?) Spring разработчик, который на самом деле не имеет отношения к теме, но кто-то подводит его в комментариях, а автор отвечает некоторой информацией:

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

Тема, которая, кажется, возникает, заключается в том, что способ решить эту проблему - определить несколько EntityManagerFactories и связать их с соответствующими репозиториями следующим образом:

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

Однако, как я уже упоминал, я хочу повторно использовать мой репозиторий во всех источниках данных, поэтому такой подход не выглядит так, как будто он будет работать.

Я знаю, что в моем коде нет логики, которая берет соответствующую информацию из запроса и использует ее для определения того, какой источник данных (или EntityManagerFactory) использовать. Часть, с которой я борюсь, - это как получить дескриптор этого источника данных /EntityManagerFactory и "вставить" его в мои объекты репозитория. Любые идеи?

Ответы

Ответ 1

Если вы действительно используете разные DataSource es в многопользовательском режиме (по существу присваивая запрос DataSource и придерживаясь его для всего запроса), вы должны посмотреть AbstractRoutingDataSource. Он по существу обеспечивает способ сохранить Map из DataSource es, а также метод обратного вызова, чтобы вернуть ключ, который будет использоваться для поиска DataSource, который будет использоваться в конечном итоге. Реализация этого метода обычно ищет какой-то связанный с потоком ключ и возвращает его (или даже карты, которые на карту карты DataSource по очереди). Вам просто нужно убедиться, что какой-то веб-компонент привязывает этот ключ к потоку в первую очередь.

Если у вас это, ваша конфигурация Spring просто устанавливает bean для вашего подкласса AbstractRoutingDataSource и прокладывает в нее карту DataSources. Ваша настройка данных JPA остается по умолчанию. EntityManagerFactoryBean относится к AbstractRoutingDataSource, и у вас есть только один элемент <jpa:repositories />.