Spring Boot 多租户:不可能设置不同的租户

问题描述 投票:0回答:1

我的问题很容易理解,但很难实现。

我有一个具有经典模式的 Spring Boot 应用程序(Controller / Service / Dao&Repository / Entity) 数据库中使用不同的模式。例如,我可以拥有 COMMON_SCHEMA.USERS 和 SPECIFIC_SCHEMA_A.ITEMS。

我认为最好的方法是实现多租户,这就是我所做的。

这是我的问题:

  1. 端点收到数据
  2. 有了这些数据,我需要在 COMMON_SCHEMA.USERS 中找到一些东西,所以我设置了正确的租户
  3. 之后,我需要在 SPECIFIC_SCHEMA_A.ITEMS 中查找数据。这就是问题发生的地方,租户未设置,并且我有一个异常,表示实体 ITEMS 不存在于架构 COMMON_SCHEMA 中。

以下是使用的主要类。

public class MultitenantDataSource extends AbstractRoutingDataSource {
  @Value("${defaultTenant}")
  private String defaultTenant;
  
  @Override
  protected Object determineCurrentLookupKey() {
    String currentTenant = TenantContext.getCurrentTenant();
    return StringUtils.defaultIfBlank(currentTenant, defaultTenant);
  }
}
public class TenantContext {
  private static final ThreadLocal<String> currentTenant = new ThreadLocal<>();
  
  public static void setCurrentTenant(String tenant) {
    currentTenant.set(tenant);
  }
  
  public static String getCurrentTenant() {
    return currentTenant.get();
  }
  
  public static void clear() {
    currentTenant.remove();
  }
}
@RestController
@RequiredArgsConstructor
public class TEST_ControllerImpl extends SessionFactoryUtil 
  implements TEST_Controller {

  private final EvGroupService evGroupService;
  
  @Override
  public ResponseEntity<?> getGrp(String token, String grp) {
    TenantContext.setCurrentTenant("COMMON_TENANT");
    EvGroup result1 = evGroupService.findByCode(grp);
    TenantContext.clear();
    
    TenantContext.setCurrentTenant("SPECIFIC_TENANT_A");
    EvGroup result2 = evGroupService.findByCode(grp);
    TenantContext.clear();
  
    return ResponseEntity.ok(convert(result1));
  }
}

希望你的火花能够照亮我的一天/一周/一个月/一年:D 谢谢

我当然尝试过ChatGpt 我尝试在服务方法签名中设置@Transactionnal注释(即使使用Transactional.TxType.REQUIRES_NEW) 看了很多帖子,但都不是和我一样的问题。

java spring spring-boot multi-tenant endpoint
1个回答
0
投票

尝试将以下属性设置为 false

spring:
  jpa:
    open-in-view: false

否则,一旦您打开数据库的会话 (

Connection
),它将保持打开状态,直到您退出控制器方法。因此,您无法真正在飞行中更改底层数据源。

您的代码中发生的情况如下:

  @Override
  public ResponseEntity<?> getGrp(String token, String grp) {
    // sets tenant
    TenantContext.setCurrentTenant("COMMON_TENANT");
    // in background creates database connection using COMMON_TENANT key
    EvGroup result1 = evGroupService.findByCode(grp);
    // clears threadlocal
    TenantContext.clear();
    
    // sets tentant to SPECIFIC_TENANT_A
    TenantContext.setCurrentTenant("SPECIFIC_TENANT_A");
    // because spring.jpa.open-in-view is set to true connection is not closed
    // but reused and still points to COMMON_TENANT
    EvGroup result2 = evGroupService.findByCode(grp);
    TenantContext.clear();
  
    return ResponseEntity.ok(convert(result1));
  }
© www.soinside.com 2019 - 2024. All rights reserved.