Вот что я в итоге делал, и это работало довольно хорошо.Менеджер сущностей может иметь только один компонент для использования в качестве источника данных.Поэтому мне нужно было создать бин, который при необходимости направлялся между ними.Именно этот Бен я использовал для менеджера сущностей JPA.
Я настроил два разных источника данных в tomcat.В server.xml я создал два ресурса (источники данных).
<Resource name="readConnection" auth="Container" type="javax.sql.DataSource"
username="readuser" password="readpass"
url="jdbc:mysql://readipaddress:3306/readdbname"
driverClassName="com.mysql.jdbc.Driver"
initialSize="5" maxWait="5000"
maxActive="120" maxIdle="5"
validationQuery="select 1"
poolPreparedStatements="true"
removeAbandoned="true" />
<Resource name="writeConnection" auth="Container" type="javax.sql.DataSource"
username="writeuser" password="writepass"
url="jdbc:mysql://writeipaddress:3306/writedbname"
driverClassName="com.mysql.jdbc.Driver"
initialSize="5" maxWait="5000"
maxActive="120" maxIdle="5"
validationQuery="select 1"
poolPreparedStatements="true"
removeAbandoned="true" />
У вас могут быть таблицы базы данных на одном сервере, и в этом случае IP-адреса или домен будут одинаковыми, просто разные БД- вы получаете jist.
Затем я добавил ссылку на ресурс в файле context.xml в tomcat, который ссылается на них на ресурсы.
<ResourceLink name="readConnection" global="readConnection" type="javax.sql.DataSource"/>
<ResourceLink name="writeConnection" global="writeConnection" type="javax.sql.DataSource"/>
Эти ссылки на ресурсы - это то, что весна читает вконтекст приложения.
В контексте приложения я добавил определение bean-компонента для каждой ссылки на ресурс и добавил одно дополнительное определение bean-компонента, которое ссылается на созданный мной bean-компонент Router Datasource, который принимает карту (перечисление) двух ранее созданных bean-компонентов (определение bean-компонента)).
<!--
Data sources representing master (write) and slaves (read).
-->
<bean id="readDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="readConnection" />
<property name="resourceRef" value="true" />
<property name="lookupOnStartup" value="true" />
<property name="cache" value="true" />
<property name="proxyInterface" value="javax.sql.DataSource" />
</bean>
<bean id="writeDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="writeConnection" />
<property name="resourceRef" value="true" />
<property name="lookupOnStartup" value="true" />
<property name="cache" value="true" />
<property name="proxyInterface" value="javax.sql.DataSource" />
</bean>
<!--
Provider of available (master and slave) data sources.
-->
<bean id="dataSource" class="com.myapp.dao.DatasourceRouter">
<property name="targetDataSources">
<map key-type="com.myapp.api.util.AvailableDataSources">
<entry key="READ" value-ref="readDataSource"/>
<entry key="WRITE" value-ref="writeDataSource"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="writeDataSource"/>
</bean>
После этого определение bean-компонента управления сущностями ссылается на bean-компонент dataSource.
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="${jpa.persistenceUnitName}" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${jpa.dialect}"/>
<property name="showSql" value="${jpa.showSQL}" />
</bean>
</property>
</bean>
Я определил некоторые свойства в файле свойств, но вы можете заменить значения $ {} наваши собственные конкретные ценности.Итак, теперь у меня есть один bean-компонент, который использует два других bean-компонента, которые представляют два моих источника данных.Один боб - тот, который я использую для JPA.Он не замечает никакой маршрутизации.
Итак, теперь компонент маршрутизации.
public class DatasourceRouter extends AbstractRoutingDataSource{
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException{
// TODO Auto-generated method stub
return null;
}
@Override
protected Object determineCurrentLookupKey(){
return DatasourceProvider.getDatasource();
}
}
Переопределенный метод вызывается менеджером сущности для определения источника данных в основном.DatasourceProvider имеет локальное (многопоточное) свойство потока с методом получения и установки, а также метод очистки источника данных для очистки.
public class DatasourceProvider{
private static final ThreadLocal<AvailableDataSources> datasourceHolder = new ThreadLocal<AvailableDataSources>();
public static void setDatasource(final AvailableDataSources customerType){
datasourceHolder.set(customerType);
}
public static AvailableDataSources getDatasource(){
return (AvailableDataSources) datasourceHolder.get();
}
public static void clearDatasource(){
datasourceHolder.remove();
}
}
У меня есть общая реализация DAO с методами, которые я использую для обработкиразличные стандартные вызовы JPA (getReference, persist, createNamedQUery & getResultList и т. д.).Прежде чем он сделает вызов entityManager, чтобы сделать все, что ему нужно, я устанавливаю источник данных DatasourceProvider для чтения или записи.Метод также может обрабатывать передаваемое значение, чтобы сделать его немного более динамичным.Вот пример метода.
@Override
public List<T> findByNamedQuery(final String queryName, final Map<String, Object> properties, final int... rowStartIdxAndCount)
{
DatasourceProvider.setDatasource(AvailableDataSources.READ);
final TypedQuery<T> query = entityManager.createNamedQuery(queryName, persistentClass);
if (!properties.isEmpty())
{
bindNamedQueryParameters(query, properties);
}
appyRowLimits(query, rowStartIdxAndCount);
return query.getResultList();
}
AvailableDataSources - это перечисление с READ или WRITE, которое ссылается на соответствующий источник данных.Вы можете видеть это на карте, определенной в моем bean-компоненте в контексте приложения.