hibernate 使用TenantConnectionResolver进行动态配置时,如何自动创建数据库和表?

sg24os4d  于 2023-10-23  发布在  其他
关注(0)|答案(1)|浏览(150)

在quarkus application.properties

quarkus.datasource.jdbc.url=jdbc:postgresql://192.168.100.110:5432/test
quarkus.datasource.username=root
quarkus.datasource.password=root
quarkus.hibernate-orm.database.generation=update
quarkus.hibernate-orm.multitenant=DATABASE

并使用TenantResolver解析tenantId

@PersistenceUnitExtension
@RequestScoped
public class CustomTenantResolver implements TenantResolver {

  @Override
  public String getDefaultTenantId() {
    return TenantUtil.NONE.toString();
  }

  @Override
  public String resolveTenantId() {
    return TenantUtil.getTenantId().toString();
  }
}

然后使用TenantConnectionResolver解析dataSource

@ApplicationScoped
@PersistenceUnitExtension
public class DataSourceTenantConnectionResolver implements TenantConnectionResolver {

  @ConfigProperty(name = "quarkus.datasource.jdbc.url")
  String url;

  @ConfigProperty(name = "quarkus.datasource.username")
  String username;

  @ConfigProperty(name = "quarkus.datasource.password")
  String password;

  private final Map<String, ConnectionProvider> map = new HashMap<>();

  @Override
  public ConnectionProvider resolve(String tenantId) {
    System.out.println("resolve ConnectionProvider " + tenantId);
    if (map.containsKey(tenantId)) {
      return map.get(tenantId);
    }
    ConnectionProvider provider;
    if (tenantId.equals(TenantUtil.NONE)) {
      provider = new QuarkusConnectionProvider(createDataSource(url, "test", username, password));
    } else {
      provider =
          new QuarkusConnectionProvider(
              createDataSource(
                  "jdbc:postgresql://192.168.100.110:5432/tenant"
                      + tenantId
                      + "?serverTimezone=Asia/Shanghai&characterEncoding=utf-8&createDatabaseIfNotExist=true",
                  "tenant" + tenantId,
                  "root",
                  "root"));
    }
    map.put(tenantId, provider);
    return provider;
  }

  private AgroalDataSource createDataSource(
      String url, String database, String username, String password) {
    try {
      AgroalDataSourceConfigurationSupplier configurationSupplier =
          new AgroalDataSourceConfigurationSupplier();
      AgroalConnectionPoolConfigurationSupplier connectionPoolConfig =
          configurationSupplier.connectionPoolConfiguration();
      connectionPoolConfig.maxSize(1000);

      AgroalConnectionFactoryConfigurationSupplier connectionFactoryConfig =
          connectionPoolConfig.connectionFactoryConfiguration();
      connectionFactoryConfig.jdbcUrl(url);
      connectionFactoryConfig.principal(new NamePrincipal(username));
      connectionFactoryConfig.credential(new SimplePassword(password));
      connectionFactoryConfig.initialSql("CREATE DATABASE IF NOT EXISTS " + database);

      return AgroalDataSource.from(configurationSupplier.get());
    } catch (SQLException | RuntimeException e) {
      throw new IllegalStateException("Exception while creating datasource for " + url, e);
    }
  }
}

问题1

无法通过createDatabaseIfNotExist=true的jdbcUrl自动创建数据库。这是预期的行为吗?所以我用connectionFactoryConfig.initialSql("CREATE DATABASE IF NOT EXISTS " + database)
问题二
如何自动创建像quarkus.hibernate-orm.database.generation=update这样的表?

ryevplcw

ryevplcw1#

无法通过DatabaseIfNotExist =true的jdbcUrl自动创建数据库。这是预期的行为吗?所以我使用了connectionFactoryConfig.initialSql(“如果不存在则创建数据库“+数据库)
参见https://stackoverflow.com/a/73669197/6692043
如何自动创建类似quarkus. hibernate-database.generation=update的表?
我不确定您是否可以直接调用Hibernate ORM来实现这一点,至少不需要付出很大的努力,因为大多数这些工具都是为单租户而设计的。
我建议您最好在开发应用程序时转储Hibernate ORM的模式初始化脚本,并在连接到新的目录时(并且您检测到它为空)手动应用这些脚本。
理想情况下,您会使用Flyway进行此类操作。但是如果你使用的是动态对象注入,你可能不能依赖Quarkus的Flyway对象注入,而必须手动构建Flyway对象。

相关问题