使用Spring,Hibernate和C3P0在多租户Web应用程序中管理连接池

使用Spring,Hibernate和C3P0在多租户Web应用程序中管理连接池,第1张

使用Spring,Hibernate和C3P0在多租户Web应用程序中管理连接

你可以选择三种会影响连接轮询的不同策略。无论如何,你都必须提供的实现

MultiTenantConnectionProvider
。你选择的策略当然会影响你的实施。

关于的一般性评论

MultiTenantConnectionProvider.getAnyConnection()

hibernate
需要
getAnyConnection()
来收集元数据并设置
SessionFactory
。通常,在多租户体系结构中,你有一个特殊/主数据库(或架构),任何租户都不使用。这是一种模板数据库(或架构)。如果此方法返回与此数据库(或架构)的连接,则可以。

策略1:每个租户都有自己的数据库。(因此它是自己的连接池)

在这种情况下,每个租户都有自己的连接池,由C3PO管理,你可以提供

MultiTenantConnectionProvider
基于
AbstractMultiTenantConnectionProvider

每个租户都有自己的租户

C3P0ConnectionProvider
,因此你要做的
selectConnectionProvider(tenantIdentifier)
就是返回正确的租户。你可以保留一个Map来缓存它们,还可以使用以下类似的方法延迟初始化
C3POConnectionProvider

private ConnectionProvider lazyInit(String tenantIdentifier){    C3P0ConnectionProvider connectionProvider = new C3P0ConnectionProvider();    connectionProvider.configure(getC3POProperties(tenantIdentifier));    return connectionProvider;}private Map getC3POProperties(String tenantIdentifier){    // here you have to get the default hibernate and c3po config properties     // from a file or from Spring application context (there are good chances    // that those default  properties point to the special/master database)     // and alter them so that the datasource point to the tenant database    // i.e. : change the property hibernate.connection.url     // (and any other tenant specific property in your architecture like :    //     hibernate.connection.username=tenantIdentifier    //     hibernate.connection.password=...    //     ...) }

策略2:每个租户在一个数据库中都有自己的架构和连接池

这种情况与关于

ConnectionProvider
实现的第一种策略非常相似,因为你还可以将其
AbstractMultiTenantConnectionProvider
用作基类来实现
MultiTenantConnectionProvider

该实现与策略1的建议实现非常相似,除了你必须更改架构而不是c3po配置中的数据库

策略3:每个租户都在单个数据库中拥有自己的架构,但使用共享的连接池

这种情况略有不同,因为每个租户都将使用相同的连接提供程序(因此将共享连接池)。在以下情况下:连接提供者必须在使用任何连接之前将模式设置为使用。即你必须实施

MultiTenantConnectionProvider.getConnection(String tenantIdentifier)
(即,由所提供的默认实施
AbstractMultiTenantConnectionProvider
将不起作用)。

使用postgresql,你可以使用:

 SET search_path to <schema_name_for_tenant>;

或使用别名

 SET schema <schema_name_for_tenant>;

所以这是你的

getConnection(tenant_identifier)
;样子:

@Overridepublic Connection getConnection(String tenantIdentifier) throws SQLException {    final Connection connection = getAnyConnection();    try {        connection.createStatement().execute( "SET search_path TO " + tenanantIdentifier );    }    catch ( SQLException e ) {        throw new HibernateException(     "Could not alter JDBC connection to specified schema [" +  tenantIdentifier + "]",     e        );    }    return connection;}

你可以在实现中结合策略1和策略2。你只需要一种方法来找到当前租户的正确连接属性/连接URL。

编辑

我认为策略2或策略3的选择取决于流量和应用程序上的租户数量。使用单独的连接池:一个租户可用的连接数量将大大减少,因此:如果某个租户出于某种合法原因突然需要许多连接,则该特定租户看到的性能将急剧下降(而另一个租户不会受影响)。

另一方面,在策略3中,如果某个租户出于某种合法原因突然需要许多联系:每个租户看到的性能都会下降。

总的来说,我认为策略2更灵活,更安全:每个租户都不能消耗超过给定数量的连接(如果需要,可以为每个租户配置此数量)



欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5017802.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-14
下一篇 2022-11-15

发表评论

登录后才能评论

评论列表(0条)

保存