多租户使用单数据库多模式,hibernate和spring引导将数据保存到错误的模式

wfypjpf4  于 2021-07-03  发布在  Java
关注(0)|答案(0)|浏览(257)

我正试图在我的多租户(单数据库,多模式)系统中植入数据,但遇到了一个问题,当我在一个数据库中使用相同的代码时,这个问题并没有出现。我完全期待在我的研究中,我错过了一些明显的东西。
每个模式将包含完全相同的表结构。
这是我的租客背景

public class TenantContext {

    public static final String DEFAULT_TENANT_IDENTIFIER = "public";

    private static final ThreadLocal<String> TENANT_IDENTIFIER = new ThreadLocal<>();

    public static void setTenant(String tenantIdentifier) {
        TENANT_IDENTIFIER.set(tenantIdentifier);
    }

    public static void reset(String tenantIdentifier) {
        TENANT_IDENTIFIER.remove();
    }

    @Component
    public static class TenantIdentifierResolver implements CurrentTenantIdentifierResolver {
        @Override
        public String resolveCurrentTenantIdentifier() {
            String currentTenantId = TENANT_IDENTIFIER.get();
            return currentTenantId != null ?
                    currentTenantId :
                    DEFAULT_TENANT_IDENTIFIER;
        }

        @Override
        public boolean validateExistingCurrentSessions() {
            return false;
        }
    }
}

还有我的冬眠图

@Configuration
public class HibernateConfig {

    @Autowired
    private JpaProperties jpaProperties;

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        return new HibernateJpaVendorAdapter();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
             MultiTenantConnectionProvider multiTenantConnectionProvider, CurrentTenantIdentifierResolver currentTenantIdentifierResolver) {

        Map<String, Object> jpaPropertiesMap = new HashMap<>();
        jpaPropertiesMap.putAll(jpaProperties.getProperties());
        jpaPropertiesMap.put(Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
        jpaPropertiesMap.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
        jpaPropertiesMap.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, TenantContext.TenantIdentifierResolver.class);

        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setPackagesToScan(UppStudentAppBeApplication.class.getPackage().getName());
        entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
        entityManagerFactoryBean.setJpaPropertyMap(jpaPropertiesMap);

        return entityManagerFactoryBean;
    }
}

和我的租户联系提供商

@Component
public class TenantConnectionProvider implements MultiTenantConnectionProvider {

    private static Logger logger = LoggerFactory.getLogger(TenantConnectionProvider.class);

    @Autowired
    private DataSource dataSource;

    public TenantConnectionProvider(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Connection getAnyConnection() throws SQLException {
        return dataSource.getConnection();
    }

    @Override
    public void releaseAnyConnection(Connection connection) throws SQLException {
        connection.close();
    }

    @Override
    public Connection getConnection(String tenantIdentifier) throws SQLException {
        logger.info("Get connection for tenant  " + String.join(":", tenantIdentifier ));
        final Connection connection = getAnyConnection();
        try {
            //connection.createStatement().execute( String.format("SET SCHEMA \"%s\";", tenantIdentifier));
            connection.setSchema(tenantIdentifier);
        } catch ( SQLException e ) {
            throw new HibernateException(
                    "Could not alter JDBC connection to specified schema [" +
                            tenantIdentifier + "]",
                    e
            );
        }
        return connection;
    }

    @Override
    public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
        try {
            //connection.createStatement().execute( String.format("SET SCHEMA \"%s\";", TenantContext.DEFAULT_TENANT_IDENTIFIER) );
            connection.setSchema(TenantContext.DEFAULT_TENANT_IDENTIFIER);
        } catch ( SQLException e ) {
            throw new HibernateException(
                    "Could not alter JDBC connection to specified schema [" +
                            tenantIdentifier + "]",
                    e
            );
        }
        releaseAnyConnection(connection);
    }

    @Override
    public boolean supportsAggressiveRelease() {
        return false;
    }

    @Override
    public boolean isUnwrappableAs(Class unwrapType) {
        return false;
    }

    @Override
    public <T> T unwrap(Class<T> unwrapType) {
        return null;
    }
}

我调用我的种子类,它使用flyway迁移构建我的租户和模式。
然后,我尝试在保存的租户之间循环切换租户上下文。当调试开始工作时。然而,当我尝试用回购做任何事情时,我得到了以下错误。
o、 h.engine.jdbc.spi.sqlexceptionhelper:错误:列campus0\ createdat不存在
提示:也许您想引用“campus0\u0.created\u at”列。
职位:32
正如我之前所说的,当它是一个单一的数据库和模式时,它工作得很好。我不能百分之百肯定我哪里出错了。我应该怎么注册模式?如果是这样的话,我怎样才能在不重新部署的情况下加入新租户?在这个阶段,我是否应该使用使用repo中模式的自定义查询?
提前感谢您的帮助或建议。
编辑1,这样我就通过检查hibernate属性,通过如下更改hibernate配置,克服了最初的障碍

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
             MultiTenantConnectionProvider multiTenantConnectionProvider,
             HibernateProperties hibernateProperties) {

        Map<String, Object> jpaPropertiesMap = hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
        //jpaPropertiesMap.putAll(jpaProperties.getProperties());
        jpaPropertiesMap.put(Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
        jpaPropertiesMap.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
        jpaPropertiesMap.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, TenantContext.TenantIdentifierResolver.class);

        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setPackagesToScan(UppStudentAppBeApplication.class.getPackage().getName());
        entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
        entityManagerFactoryBean.setJpaPropertyMap(jpaPropertiesMap);

        return entityManagerFactoryBean;
}

这已经消除了上述命名错误。但是现在它保存到我的默认模式,而不是tenantidentifierresolver中设置的模式。

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题