Hibernateのマルチテナントデータベースアーキテクチャ を実装しました。この場合、テナントに応じて特定のデータベース接続が選択されます。 Spring 4.3とHibernate 5.2を使用しています。
テナントが同じRDBMSを使用している場合はすべて問題ありませんが、異なる場合は、Hibernateプロパティの方言設定を動的に変更する必要があります。
私の休止状態のプロパティはdispatcher-servlet.xmlにあります:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example"/>
<mvc:annotation-driven/>
<context:property-placeholder location="classpath:application.properties"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" >
<property name="packagesToScan">
<list>
<value>com.example.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<!--<prop key="hibernate.dialect">${hibernate.dialect}</prop>-->
<prop key="hibernate.show_sql">${hibernate.show_sql:false}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql:false}</prop>
<prop key="hibernate.multiTenancy">DATABASE</prop>
<prop key="hibernate.tenant_identifier_resolver">com.example.multitenancy.CurrentTenantIdentifierResolverImpl</prop>
<prop key="hibernate.multi_tenant_connection_provider">com.example.multitenancy.MultiTenantConnectionProviderImpl</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
以下は、HibernateのCurrentTenantIdentifierResolverの実装です。
public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
@Override
public String resolveCurrentTenantIdentifier() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return Helper.getTenantFromAuthentication(authentication);
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}
}
AbstractDataSourceBasedMultiTenantConnectionProviderImplの実装:
public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
@Override
protected DataSource selectAnyDataSource() {
return getDataSource("tenantId1");
}
@Override
protected DataSource selectDataSource(String tenantIdentifier) {
return getDataSource(tenantIdentifier);
}
private DataSource getDataSource(String prefix) {
Properties properties = new Properties();
try {
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("application.properties"));
} catch (IOException e) {
throw new RuntimeException();
}
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(properties.getProperty(prefix + ".driverClassName"));
dataSource.setUrl(properties.getProperty(prefix + ".url"));
dataSource.setUsername(properties.getProperty(prefix + ".username"));
dataSource.setPassword(properties.getProperty(prefix + ".password"));
return dataSource;
}
}
application.propertiesファイルは次のようになります。
tenantId1.driverClassName = org.postgresql.Driver
tenantId1.url = <...>
tenantId1.username = <...>
tenantId1.password = <...>
tenantId2.driverClassName = com.mysql.jdbc.Driver
tenantId2.url = <...>
tenantId2.username = <...>
tenantId2.password = <...>
休止状態の方言を動的に変更する方法はありますか?
単一の休止状態構成ファイルを使用して達成することはできません。データベースごとに異なる構成ファイルが必要です。
たとえば、2つのデータベースMySqlとOracleがあるとします。
MySQLデータベースを設定するには
hibernate-mysql.cfg.xml
Oracleデータベースを構成するには
hibernate-Oracle.cfg.xml
2つの異なるセッションを作成すると、コードは次のようになります。
private static SessionFactory sessionAnnotationFactory;
sessionAnnotationFactory = new Configuration().configure("hibernate-mysql.cfg.xml").buildSessionFactory();
Session MySqlSession = sessionAnnotationFactory.openSession();
Oracleデータベース構成の場合
sessionAnnotationFactory = new Configuration().configure("hibernate-Oracle.cfg.xml").buildSessionFactory();
Session OracleSession = sessionAnnotationFactory.openSession()
2つの異なるデータベースに対して2つのセッションファクトリオブジェクトを作成する必要があると思います。
ここを参照してください: Hibernateが複数のデータソースと複数のセッションファクトリを構成する
または、以下の私のsolを参照して、懸念がある場合は教えてください。
LocalSessionFactoryBeanのsetHibernateProperties(Java.util.Properties hibernateProperties)メソッドを使用して、hibernate.dialectを変更できます。
Springを通じて休止状態のセッションファクトリーBeanを注入しました。したがって、SpringコンテナーからBeanを取得し、休止状態のプロパティを変更するだけです。以下では、セッションファクトリに方言のみを追加しましたが、必要なプロパティをすべて設定することをお勧めします。
以下の方法は、参照と理解のためのものであり、必要に応じてロジックとパラメーターを変更します。
休止状態の方言を変更したい場合は、以下のメソッドを呼び出してください。
@Autowired
private LocalSessionFactoryBean sessionFactory;
//Change the logic and parameters as needed.
public void changedialect(String database) {
Properties prop=new Properties();
String dialect="org.hibernate.dialect.MySQLDialect";
if("postgresql".equals(database)) dialect="org.hibernate.dialect.PostgreSQLDialect";
prop.setProperty("hibernate.dialect", dialect);
sessionFactory.setHibernateProperties(prop);
}
純粋に注釈ベースの構成を使用してこれを実現できなかった理由はわかりません。私は方言を次のように設定しました:
properties.put("hibernate.dialect", "org.hibernate.dialect.SQLServerDialect");
実際には、構成ファイルの値がONに設定されている場合に、いくつかのテストデータとともにデータベースを完全に再構築するコードを配置しています。完全にJavaベースの構成に切り替えることで同じことができるはずです。