今天我们来讨论多租户和当前会话功能之间的交互。
多租户允许您在不同的租户之间隔离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分区或抛出异常。如果你有意见,请参与讨论!
同时,使用上述选项之一。