これは、他に選択肢がない場合を除いて、私がお勧めしないソリューションです。レベル2キャッシュは、このようなソリューションでは機能しない可能性がありますが、基盤となるレガシーデータベースが1つにマージされるまで、時間を購入するために使用することを余儀なくされた(安定した)ソリューションです。
まず、JBossのstandalone.xmlで、データベース接続をXAデータソースとして設定します。MS SQLサーバーを使用している場合は、 http://msdn.microsoft.com/en-us/library/aa342335.aspxでXAを適切にセットアップする方法の指示に従ってください。
スタンドアロン.xml
<datasources>
<datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<xa-datasource jta="true" jndi-name="java:jboss/datasources/MYDB_ONE" pool-name="MYDB_ONE" enabled="true" use-java-context="true" use-ccm="true">
<xa-datasource-property name="ServerName">
localhost
</xa-datasource-property>
<xa-datasource-property name="DatabaseName">
MYDB_ONE
</xa-datasource-property>
<xa-datasource-property name="SelectMethod">
cursor
</xa-datasource-property>
<xa-datasource-class>com.microsoft.sqlserver.jdbc.SQLServerXADataSource</xa-datasource-class>
<driver>sqljdbc</driver>
<xa-pool>
<is-same-rm-override>false</is-same-rm-override>
</xa-pool>
<security>
<user-name>some_user</user-name>
<password>some_password</password>
</security>
<validation>
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLValidConnectionChecker"/>
</validation>
</xa-datasource>
<xa-datasource jta="true" jndi-name="java:jboss/datasources/MYDB_TWO" pool-name="MYDB_TWO" enabled="true" use-java-context="true" use-ccm="true">
<xa-datasource-property name="ServerName">
localhost
</xa-datasource-property>
<xa-datasource-property name="DatabaseName">
MYDB_TWO
</xa-datasource-property>
<xa-datasource-property name="SelectMethod">
cursor
</xa-datasource-property>
<xa-datasource-class>com.microsoft.sqlserver.jdbc.SQLServerXADataSource</xa-datasource-class>
<driver>sqljdbc</driver>
<xa-pool>
<is-same-rm-override>false</is-same-rm-override>
</xa-pool>
<security>
<user-name>some_user</user-name>
<password>some_password</password>
</security>
<validation>
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLValidConnectionChecker"/>
</validation>
</xa-datasource>
<drivers>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
<driver name="sqljdbc" module="com.microsoft.sqlserver.jdbc">
<driver-class>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver-class>
</driver>
<driver name="postgresql" module="org.postgresql">
<xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
次に、AbstractRoutingDataSourceの実装をdataSourceとして使用するentityManagerBeanをセットアップします。これは、persistence.xmlファイルを使用しないSpringベースのJPAセットアップです。私の知る限り、JBoss7を使用するときにエンティティの自動パッケージスキャンを取得する唯一の方法はこれです。
springJpaConfig.xml
<!-- Use @PersistenceContext annotations for injecting entity managers -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<!-- Set up JTA transaction manager -->
<tx:jta-transaction-manager />
<bean id="entityManagerFactoryMyDB" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="MyDB" />
<property name="dataSource" ref="dataSourceMyDB" />
<property name="packagesToScan" value="my.package.with.jpa.entities" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="javax.persistence.transactionType" value="jta" />
<entry key="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
<entry key="jboss.entity.manager.factory.jndi.name" value="java:app/MyDBEntityManagerFactory" />
<entry key="hibernate.dialect" value="org.hibernate.dialect.SQLServer2008Dialect" />
</map>
</property>
</bean>
<bean id="dataSourceMyDB" class="some.package.AbstractRoutingDataSourceMyDB">
<property name="lenientFallback" value="false" />
<property name="defaultTargetDataSource" value="java:jboss/datasources/ExampleDS" />
<property name="targetDataSources">
<map key-type="String">
<!-- This is a placeholder that will be filled in by BeanFactoryPostProcessor -->
</map>
</property>
</bean>
<!-- This allows us to modify Spring configuration load the list of datasources -->
<bean class="some.package.DatasourceRegisteringBeanFactoryPostProcessor" />
defaultTargetDataSourceを指定する必要があるため、AbstractRoutingDataSourceMyDBのデフォルトとしてExampleDSを使用しますが、常に有効なDBを手動で選択したいので、最初に接続を手動で選択せずにDBにアクセスしようとすると、クエリを実行しようとします。例外をスローする存在しないExampleDSデータベース(非常にハッキーですが、作業は完了します)。
BeanFactoryPostProcessorで、データソースのリストに入力する必要があります。
DatasourceRegisteringBeanFactoryPostProcessor.java
package some.package
class DatasourceRegisteringBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
HashMap<String, String> connectionsListMyDB = new HashMap<>();
// Load your connection list from wherever you need to, you can
// enumerate them directly from JNDI or some configuration location
connectionsListMyDB.put("db1", "java:jboss/datasources/MYDB_ONE");
connectionsListMyDB.put("db2", "java:jboss/datasources/MYDB_TWO");
if (connectionsList.isEmpty())
throw new RuntimeException("No JPA connections defined");
// Configure the dataSource bean properties
BeanDefinitionRegistry factory = (BeanDefinitionRegistry) beanFactory;
MutablePropertyValues mpv = factory.getBeanDefinition("dataSourceMyDB").getPropertyValues();
ManagedMap<String, String> mm = (ManagedMap<String, String>) mpv.getPropertyValue(
"targetDataSources").getValue();
mm.clear();
for (Entry<String, String> e : connectionsListMyDB.entrySet()) {
mm.put(e.getKey(), e.getValue());
}
}
}
これは、実行時に接続を切り替えることができるAbstractRoutingDataSourceの実装です。
AbstractRoutingDataSourceMyDB.java
public class AbstractRoutingDataSourceMyDB extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return getDbConnectionMyDB();
}
// ThreadLocal variable so that the connection gets set for the current thread
// using spring's request scope on the class instead of ThreadLocal would also work here.
private final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public void setDbConnectionMyDB(String myKey) {
Assert.notNull(myKey, "myKey cannot be null");
contextHolder.set(myKey);
String k = contextHolder.get();
}
public String getDbConnectionMyDB() {
return (String) contextHolder.get();
}
public void clearDbConnectionMyDB() {
contextHolder.remove();
}
}
DAOクラス内から現在の接続を変更する前に、entitymanager.flush()とclear()を呼び出す必要があることに注意してください。そうしないと、トランザクションのスコープ内のすべての保留中の操作が、トランザクションのコミット時に新しい接続で実行されます。これは、Hibernateセッションが、接続が変更されたことを認識していないためです。これは、接続が常に同じデータベースであることがわかっている限りです。
したがって、DAOでは、これを今すぐ実行できます。
SomeTableDAO.java
@PersistenceContext(unitName = "MyDB")
private EntityManager em;
@Autowired
private AbstractRoutingDataSourceMyDB routingSource;
public void someMethod(int id) {
em.flush();
em.clear();
routingSource.setDbConnectionMyDB("db1");
em.remove(em.getReference(Something.class, id)); // delete something in db1
em.flush();
em.clear();
routingSource.setDbConnectionMyDB("db2");
em.remove(em.getReference(Something.class, id)); // delete something else with the same id in db2
}
それで、あなたは行きます、それはきれいではありませんが-それはすることができます:)