以前の回答を削除する必要があるかどうかわかりません。eそれか何かを言いなさい。 MODが私に適切な手続きを知らせることができれば、私は喜んで遵守するでしょう。
私は、@Transactional
の使用については正しく機能しませんでした。私はMultiTenantConnectionProviderImpl
とCurrentTenantResolverImpl
の代わりにAbstractRoutingDataSource
のカスタム実装を使用しました。私はこの新しいデータソースを使用する代わりにhibernate.multiTenancy
hibernate.multi_tenant_connection_provider
とhibernate.tenant_identifier_resolver
私の一時的なオーバーライドクラスを設定すると、次のようになります。
public class MultitenancyTemporaryOverride implements AutoCloseable
{
static final ThreadLocal<String> tenantOverride = new NamedThreadLocal<>("temporaryTenantOverride");
public void setCurrentTenant(String tenantId)
{
tenantOverride.set(tenantId);
}
public String getCurrentTenant()
{
return tenantOverride.get();
}
@Override
public void close() throws Exception
{
tenantOverride.remove();
}
}
マイTenantRoutingDataSourceは次のようになります。
@Component
public class TenantRoutingDataSource extends AbstractDataSource implements InitializingBean
{
@Override
public Connection getConnection() throws SQLException
{
return determineTargetDataSource().getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException
{
return determineTargetDataSource().getConnection(username, password);
}
@Override
public void afterPropertiesSet() throws Exception
{
}
protected String determineCurrentLookupKey()
{
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String database = "shared";
if (authentication != null && authentication.getPrincipal() instanceof MyUser)
{
MyUser user = (MyUser) authentication.getPrincipal();
database = user.getTenantId();
}
String temporaryOverride = MultitenancyTemporaryOverride.tenantOverride.get();
if (temporaryOverride != null)
{
database = temporaryOverride;
}
return database;
}
protected DataSource determineTargetDataSource()
{
return selectDataSource(determineCurrentLookupKey());
}
public DataSource selectDataSource(String tenantIdentifier)
{
//I use C3P0 for my connection pool
PooledDataSource pds = C3P0Registry.pooledDataSourceByName(tenantIdentifier);
if (pds == null)
pds = getComboPooledDataSource(tenantIdentifier);
return pds;
}
private ComboPooledDataSource getComboPooledDataSource(String tenantIdentifier)
{
ComboPooledDataSource cpds = new ComboPooledDataSource(tenantIdentifier);
cpds.setJdbcUrl("A JDBC STRING HERE");
cpds.setUser("MyDbUsername");
cpds.setPassword("MyDbPassword");
cpds.setInitialPoolSize(10);
cpds.setMaxConnectionAge(10000);
try
{
cpds.setDriverClass("com.informix.jdbc.IfxDriver");
}
catch (PropertyVetoException e)
{
throw new RuntimeException("Weird error when setting the driver class", e);
}
return cpds;
}
}
その後、私はちょうど提供します私のカスタムデータソースを、Entity ManagerファクトリBeanに作成するときに、
@Service
public class TestService
{
public void doSomeGets()
{
List<String> tenants = getListSomehow();
try(MultitenancyTemporaryOverride tempOverride = new MultitenancyTemporaryOverride())
{
for(String tenant : tenants)
{
tempOverride.setCurrentTenant(tenant);
//do some work here, which only applies to the tenant
}
}
catch (Exception e)
{
logger.error(e);
}
}
}
「設定を読み込む」とは、各テナントのデータベース内のテーブルを意味しますか?このブログ[post](http://anakiou.blogspot.my/2015/08/multi-tenant-application-with-spring.html)を見てみるとよいでしょう。データソースのリストがある場合は、アプリケーションの起動時にループするのが難しくないと思います。 – Mustafa
「構成表」を例として使用すると、物事を混乱させる可能性があるため、悪い選択であった可能性があります。私は実際には、さまざまな理由ですべてのテナントの間で読む必要があるいくつかのことがあります。あなたが提供するブログ記事は、私が知らないデータソースを知っていることを示唆しています。 –
マルチテナントとは、データベースサーバ上の 'dropbox_db'、' google_drive_db'、 'sky_drive_db'などの複数のデータベースに表示される' users'というテーブルを持つようなものですか? – Saheed