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