多租户数据库和新线程

3
我已经使用MultiTenantConnectionProviderCurrentTenantIdentifierResolver在我的Spring Boot应用程序中实现了数据库多租户。我有一个静态的数据库连接实例和一个动态的多租户连接实例,一切都运行正常,直到我被迫使用多线程技术。
新线程似乎会丢失关于动态连接的信息(静态连接没有问题),所以我的问题是,有没有可能将连接信息传递给新线程,以便能够像通常一样使用JPA Repository?
感谢回答和建议。

我有同样的问题,如果有人有解决方案并能回复,那就太好了。谢谢。 - Righto
如果多租户在多线程中失败,那真的是一个错误。但不确定是否属于该情况。我正在使用ExecutorService,似乎丢失了当前租户标识符的信息。 - Righto
3个回答

2
我们需要将当前线程中的“租户ID”传递到新创建的线程中,以在多租户模式下工作。为此,我们必须按以下方式维护TenantContext:Original Answer。
public class TenantContext {
    private static final ThreadLocal<Tenant> tenantHolder = new ThreadLocal<>();

    public static Tenant getTenant() {
        Tenant tenant = tenantHolder.get();
        return Objects.isNull(tenant) ? Tenant.DEFAULT : tenant;
    }

    public static void setTenant(Tenant tenant) {
        tenantHolder.set(tenant);
    }

    public static void clearTenant() {
        tenantHolder.remove();
    }
}
Tenant是一个枚举类型,包含所有租户ID。在创建新线程之前,我们必须先解析租户并将其设置为TenantContext
现在,我们需要编写新的自定义线程类。
"Original Answer"翻译成中文是"最初的回答"。
public class TenantAwareThread extends Thread {
    private Tenant tenant = null;

    public TenantAwareThread(Runnable target) {
        super(target);
        this.tenant = TenantContext.getTenant();
    }

    @Override
    public void run() {
        TenantContext.setTenant(this.tenant);
        super.run();
        TenantContext.clearTenant();
    }
}

最终,我们可以按照以下方式创建线程:

new TenantAwareThread(() -> {
    //do operation
}).start();

新线程将自动获取租户ID并正确访问相应租户的数据库。

原始答案翻译成“最初的回答”。



1

0

要么将租户ID/信息作为URL的一部分或者作为Header在请求中传递,并使用过滤器通过Tenant Holder/Context将其设置为ThreadLocal。

我在使用Spring Boot、JPA、Hibernate和Postgres构建多租户应用程序中写过关于此的博客。

我很快会写一篇关于如何通过TenantStore传递租户数据以防止直接操作ThreadLocal并支持在服务、资源等中注入TenantStore的博客。


我实际上是在使用您的博客作为多租户实现的示例,但是在新线程上没有关于实际租户的信息的问题。 - rdabrowski
我没有理解“新线程上没有实际租户信息”的意思。您能否详细说明一下?如果我没记错的话,在ResolverImpl类中,如果没有传递租户ID,则会解析为“tenant_1”。 - ootero

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接