多租户和当前会话

作者:    |       Hibernate ORM

今天我们来讨论多租户和当前会话功能之间的交互。

多租户允许您在不同的租户之间隔离Session操作。这有助于创建一个单一的应用程序,将不同的客户相互隔离。

当前会话功能会为给定上下文(通常是(JTA)事务)返回相同的会话。这有助于实现每个视图/事务/对话一个会话的模式,并避免每个操作一个会话的反模式。

Session session = sessionFactory.getCurrentSession();
// do some other work
[...]
// later in the same context (e.g. JTA Transaction)
Session session2 = sessionFactory.getCurrentSession();

// semantically we have
assert session == session2

这两个功能可以很好地协同工作,只需简单实现CurrentTenantIdentifierResolver。这将为Hibernate ORM在创建当前会话时提供预期的租户ID。

当前意味着什么?

在与Florian和ToulouseJUG讨论时,我们交流了一个小案例,其中事情可能不会按预期工作。Hibernate ORM认为,对于给定上下文(例如事务),只能有一个当前Session

因此,如果在相同的上下文(例如事务)中

  • 您的CurrentTenantIdentifierResolver实现返回不同的租户ID,

  • 您使用getCurrentSession()

您将得到一个TenantIdentifierMismatchException

然而,有时从同一上下文(例如同一事务)访问多个租户很有用。您有两个选项

  • 手动创建Session

  • 实现自定义的CurrentSessionContext

手动创建Session

您可以使用SessionFactory API为所需的租户ID创建一个Session

Session session1 = sessionFactory.withOptions()
        .tenantIdentifier( tenant1 )
        ...
        .openSession();
Session session2 = sessionFactory.withOptions()
        .tenantIdentifier( tenant2 )
        ...
        .openSession();

但您必须确保关闭这些会话。如果您习惯于CDI或Spring为您处理会话,或者如果您依赖当前会话功能在您的堆栈中传播会话,这可能会很麻烦。

实现自定义的CurrentSessionContext

另一种选择是实现自己的CurrentSessionContext版本,避免抛出TenantIdentifierMismatchException异常,并按上下文标识和租户ID分别保留Session实例。

在实践中,当前会话存储在以上下文标识为键的ConcurrentHashMap中,你只需要改进这一部分。从JTASessionContext开始,进行修改!

现在怎么办?

我们目前正在讨论默认的CurrentSessionContext实现是否应该按租户ID分区或抛出异常。如果你有意见,请参与讨论

同时,使用上述选项之一。


回到顶部