Hibernate Spring boot 2多租户配置不使用事务

Hibernate Spring boot 2多租户配置不使用事务,hibernate,spring-boot,spring-data-jpa,multi-tenant,Hibernate,Spring Boot,Spring Data Jpa,Multi Tenant,我有一个SpringBoot2应用程序运行良好。我引入了多租户配置,现在它不再工作了 我举了一个例子: 注意:我使用的是HibernateTrasactionMaanger,但是,在我的研究过程中,如果您使用: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</ar

我有一个SpringBoot2应用程序运行良好。我引入了多租户配置,现在它不再工作了

我举了一个例子:

注意:我使用的是HibernateTrasactionMaanger,但是,在我的研究过程中,如果您使用:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
这就是我的应用程序现在的样子:

应用程序属性

# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.driver-class-name=@database.driverClassName@
spring.datasource.url=@database.url@
spring.datasource.username=@database.username@
spring.datasource.password=@database.password@
spring.datasource.name=prohome_tenant_directory
spring.datasource.hikari.maximumPoolSize=@database.maxPoolSize@

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.id.new_generator_mappings=false
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
PersistenceConfiguration.java:

@Configuration
@EnableTransactionManagement
public class PersistenceConfiguration {

    @Autowired
    private JpaProperties jpaProperties;

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

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            DataSource dataSource,
            MultiTenantConnectionProvider multiTenantConnectionProviderImpl,
            CurrentTenantIdentifierResolver currentTenantIdentifierResolverImpl
    ) {

        Map<String, Object> jpaPropertiesMap = new HashMap<>(jpaProperties.getProperties());
        jpaPropertiesMap.put(Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
        jpaPropertiesMap.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProviderImpl);
        jpaPropertiesMap.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolverImpl);

        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource);
        em.setPackagesToScan("com.example.orm", "com.example.orm.tenant");
        em.setJpaVendorAdapter(this.jpaVendorAdapter());
        em.setJpaPropertyMap(jpaPropertiesMap);

        return em;
    }

}
GenericDao.java:

public abstract class GenericDao<T, PK extends Serializable> extends BaseDao {

    private final Class<T> type;

    public GenericDao(Class<T> type) {
        this.type = type;
    }

    public T getById(PK id) throws DatabaseException {

        try {

            return getSession().get(type, id);

        } catch (HibernateException ex) {
            throw new DatabaseException(ex);
        }
    }

    public <T> T getEntityByIdAndType(String id, Class<T> entityClass) throws DatabaseException {

        try {

            return getSession().get(entityClass, id);

        } catch (HibernateException ex) {
            throw new DatabaseException(ex);
        }
    }

    public T save(T entity) throws DatabaseException {

        try {

            Session session = getSession();

            session.save(entity);

            return entity;

        } catch (HibernateException ex) {
            throw new DatabaseException(ex);
        }
    }


    //Other methods ommited.


}
租户数据源DAO:

@Repository
public class TenantDataSourceDao extends GenericDao<TenantDataSource, String> {

    public TenantDataSourceDao() {
        super(TenantDataSource.class);
    }

    public TenantDataSource getByName(String name) throws DatabaseException {

        try {

            Session session = getSession();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<TenantDataSource> query = builder.createQuery(TenantDataSource.class);

            Root<TenantDataSource> root = query.from(TenantDataSource.class);
            query.where(builder.equal(root.get("name"), name));

            TenantDataSource tenant = session.createQuery(query).uniqueResult();

            return tenant;

        } catch (HibernateException ex) {
            throw new DatabaseException(ex);
        }
    }
}
TenantConnectionProvider.java

@Component
public class TenantConnectionProvider extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {

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

    @Autowired
    private DataSource directoryDataSource;

    @Autowired
    private ApplicationContext context;

    //DataSource map.
    private final Map<String, DataSource> map = new HashMap<>();

    //Init flag.
    private boolean init = false;

    public TenantConnectionProvider() {
    }

    @PostConstruct
    public void load() {
        map.put(TenantConstants.DEFAULT_TENANT_ID, directoryDataSource);
    }

    @Override
    protected DataSource selectAnyDataSource() {
        return map.get(TenantConstants.DEFAULT_TENANT_ID);
    }

    @Override
    protected DataSource selectDataSource(String tenantIdentifier) {

        if (!init) {
            init = true;
            TenantDataSourceService tenantDataSourceService = context.getBean(TenantDataSourceService.class);
            map.putAll(tenantDataSourceService.getAll());
        }

        return map.get(tenantIdentifier) != null ? map.get(tenantIdentifier) : map.get(TenantConstants.DEFAULT_TENANT_ID);
    }

}
@组件
公共类TenantConnectionProvider扩展了AbstractDataSourceBasedMultiTenantConnectionProviderImpl{
私有最终静态记录器Logger=LoggerFactory.getLogger(TenantConnectionProvider.class);
@自动连线
私有数据源目录数据源;
@自动连线
私有应用程序上下文上下文;
//数据源映射。
私有最终映射=新HashMap();
//初始化标志。
私有布尔init=false;
公共租户连接提供程序(){
}
@施工后
公共空荷载(){
put(TenantConstants.DEFAULT_TENANT_ID,directoryDataSource);
}
@凌驾
受保护的数据源selectAnyDataSource(){
返回map.get(TenantConstants.DEFAULT_TENANT_ID);
}
@凌驾
受保护的数据源selectDataSource(字符串租户标识符){
if(!init){
init=真;
TenantDataSourceService TenantDataSourceService=context.getBean(TenantDataSourceService.class);
putAll(tenantDataSourceService.getAll());
}
返回map.get(tenantIdentifier)!=null?map.get(tenantIdentifier):map.get(TenantConstants.DEFAULT\u租户ID);
}
}
TenantContext.java,通过在请求中查找tenantId在任何其他操作之前的筛选器中设置

public class TenantContext {

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

    public static String getCurrentTenant() {
        return CURRENT_TENANT.get();
    }

    public static void setCurrentTenant(String tenant) {
        clear();
        CURRENT_TENANT.set(tenant);
    }

    public static void clear() {
        CURRENT_TENANT.set(null);
    }
}
公共类租户上下文{
私有静态最终ThreadLocal当前_租户=新的InheritableThreadLocal();
公共静态字符串getCurrentTenant(){
返回当前_租户。get();
}
公共静态无效setCurrentTenant(字符串租户){
清除();
当前_租户集(租户);
}
公共静态无效清除(){
当前租户集(空);
}
}
这是我得到的堆栈跟踪:

[2020-05-20 15:32:38,903] [main] [DEBUG] [com.example.tenant.TenantDataSourceService.getAll] [user=n/d] - Initializing ALL Tenant DataSources
[2020-05-20 15:32:38,915] [main] [ERROR] [com.example.tenant.TenantDataSourceService.getAll] [user=n/d] - Can not load ALL Tenant DataSources
com.example.exception.DatabaseException: Database error occurred
    at com.example.dao.GenericDao.getAll(GenericDao.java:134)
    at com.example.dao.GenericDao$$FastClassBySpringCGLIB$$a026e92f.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
    at com.example.tenant.TenantDataSourceDao$$EnhancerBySpringCGLIB$$646b253f.getAll(<generated>)
    at com.example.tenant.TenantDataSourceService.getAll(TenantDataSourceService.java:39)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416)
Caused by: org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.orm.hibernate5.SpringSessionContext.currentSession(SpringSessionContext.java:143)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:514)
    at com.example.dao.BaseDao.getSession(BaseDao.java:33)
    at com.example.dao.GenericDao.getAll(GenericDao.java:121)
    at com.example.dao.GenericDao$$FastClassBySpringCGLIB$$a026e92f.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
    at com.example.tenant.TenantDataSourceDao$$EnhancerBySpringCGLIB$$646b253f.getAll(<generated>)
    at com.example.tenant.TenantDataSourceService.getAll(TenantDataSourceService.java:39)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
[2020-05-20 15:32:38,927] [main] [INFO ] [org.springframework.scheduling.concurrent.ExecutorConfigurationSupport.initialize] [user=n/d] - Initializing ExecutorService 'emailThreadPoolTaskExecutor'
[2020-05-20 15:32:39,626] [main] [INFO ] [org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.getOrDeducePassword] [user=n/d] - 
[2020-05-20 15:32:38903][main][DEBUG][com.example.tenant.TenantDataSourceService.getAll][user=n/d]-初始化所有租户数据源
[2020-05-20 15:32:38915][main][ERROR][com.example.tenant.TenantDataSourceService.getAll][user=n/d]-无法加载所有租户数据源
com.example.exception.DatabaseException:发生数据库错误
位于com.example.dao.GenericDao.getAll(GenericDao.java:134)
在com.example.dao.GenericDao$$FastClassBySpringCGLIB$$a026e92f.invoke()上
位于org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
位于org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
在org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:163)上
位于org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.procedue(CglibAopProxy.java:747)
位于org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
位于org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:186)
位于org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.procedue(CglibAopProxy.java:747)
位于org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
在com.example.tenant.TenantDataSourceDao$$EnhancerBySpringCGLIB$$646b253f.getAll()上
位于com.example.tenant.TenantDataSourceService.getAll(TenantDataSourceService.java:39)
位于java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(本机方法)
位于java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
位于java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
位于java.base/java.lang.reflect.Method.invoke(Method.java:567)
位于org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
位于org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)
位于org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416)上
原因:org.hibernate.HibernateException:无法获取当前线程的事务同步会话
位于org.springframework.orm.hibernate5.SpringSessionContext.currentSession(SpringSessionContext.java:143)
位于org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:514)
位于com.example.dao.BaseDao.getSession(BaseDao.java:33)
位于com.example.dao.GenericDao.getAll(GenericDao.java:121)
在com.example.dao.GenericDao$$FastClassBySpringCGLIB$$a026e92f.invoke()上
位于org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
位于org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
在org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:163)上
位于org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.procedue(CglibAopProxy.java:747)
位于org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationIntercep
@Service
public class TenantDataSourceService {

    private final static Logger LOGGER = LoggerFactory.getLogger(TenantDataSourceService.class);

    @Autowired
    private TenantDataSourceDao dataSourceDao;

    private final Map<String, DataSource> tenantDataSources = new HashMap<>();

    @PostConstruct
    @Transactional(readOnly = true)
    public Map<String, DataSource> getAll() {

        LOGGER.debug("Initializing ALL Tenant DataSources");

        try {
            List<TenantDataSource> tenants = dataSourceDao.getAll();

            LOGGER.debug("Found {} tenants", tenants.size());

            Map<String, DataSource> result = new HashMap<>();

            for (TenantDataSource config : tenants) {

                LOGGER.debug("Configuring DS for tenant {}", config.getName());
                DataSource dataSource = getDataSource(config.getName());
                result.put(config.getName(), dataSource);
            }

            return result;

        } catch (DatabaseException ex) {
            LOGGER.error("Can not load ALL Tenant DataSources", ex);
            return null;
        }
    }

    /**
     * Returns a data source based on the tenant name.
     * 
     * If not exists attempts to create it.
     * 
     * @param name
     * @return
     * @throws DatabaseException 
     */
    protected DataSource getDataSource(String name) throws DatabaseException {

        LOGGER.debug("Requesting dataSource for tenant={}", name);

        //The DataSource was already added just return it.
        if (tenantDataSources.get(name) != null) {

            LOGGER.debug("DataSource for tenant {} was already created", name);
            return tenantDataSources.get(name);
        }

        //Create the data source and add it to the data sources map.
        DataSource dataSource = createDataSource(name);

        if (Objects.nonNull(dataSource)) {
            tenantDataSources.put(name, dataSource);
        }

        return dataSource;
    }

    /**
     * Creates a DataSource from the Tenant configuration in the database.
     * 
     * @param name
     * @return 
     */
    private DataSource createDataSource(String name) throws DatabaseException {

        LOGGER.debug("Creating dataSource for tenant={}", name);

        TenantDataSource tenantDataSource = dataSourceDao.getByName(name);

        if (Objects.nonNull(tenantDataSource)) {

            DataSourceBuilder factory = DataSourceBuilder
                    .create()
                    .driverClassName(tenantDataSource.getDbDriverClassName())
                    .username(tenantDataSource.getDbUsername())
                    .password(tenantDataSource.getDbPassword())
                    .url(tenantDataSource.getDbUrl());

            DataSource ds = factory.build();    

            return ds;
        }

        return null;
    }   
}
@Component
public class TenantIdentifierResolver implements CurrentTenantIdentifierResolver {

    private final static Logger LOGGER = LoggerFactory.getLogger(TenantIdentifierResolver.class);

    @Override
    public String resolveCurrentTenantIdentifier() {

        String tenant = Objects.requireNonNullElse(TenantContext.getCurrentTenant(), TenantConstants.DEFAULT_TENANT_ID);

        LOGGER.debug("Identified tenant as: [{}]", tenant);

        return tenant;
    }

    @Override
    public boolean validateExistingCurrentSessions() {

        return true;
    }

}
@Component
public class TenantConnectionProvider extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {

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

    @Autowired
    private DataSource directoryDataSource;

    @Autowired
    private ApplicationContext context;

    //DataSource map.
    private final Map<String, DataSource> map = new HashMap<>();

    //Init flag.
    private boolean init = false;

    public TenantConnectionProvider() {
    }

    @PostConstruct
    public void load() {
        map.put(TenantConstants.DEFAULT_TENANT_ID, directoryDataSource);
    }

    @Override
    protected DataSource selectAnyDataSource() {
        return map.get(TenantConstants.DEFAULT_TENANT_ID);
    }

    @Override
    protected DataSource selectDataSource(String tenantIdentifier) {

        if (!init) {
            init = true;
            TenantDataSourceService tenantDataSourceService = context.getBean(TenantDataSourceService.class);
            map.putAll(tenantDataSourceService.getAll());
        }

        return map.get(tenantIdentifier) != null ? map.get(tenantIdentifier) : map.get(TenantConstants.DEFAULT_TENANT_ID);
    }

}
public class TenantContext {

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

    public static String getCurrentTenant() {
        return CURRENT_TENANT.get();
    }

    public static void setCurrentTenant(String tenant) {
        clear();
        CURRENT_TENANT.set(tenant);
    }

    public static void clear() {
        CURRENT_TENANT.set(null);
    }
}
[2020-05-20 15:32:38,903] [main] [DEBUG] [com.example.tenant.TenantDataSourceService.getAll] [user=n/d] - Initializing ALL Tenant DataSources
[2020-05-20 15:32:38,915] [main] [ERROR] [com.example.tenant.TenantDataSourceService.getAll] [user=n/d] - Can not load ALL Tenant DataSources
com.example.exception.DatabaseException: Database error occurred
    at com.example.dao.GenericDao.getAll(GenericDao.java:134)
    at com.example.dao.GenericDao$$FastClassBySpringCGLIB$$a026e92f.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
    at com.example.tenant.TenantDataSourceDao$$EnhancerBySpringCGLIB$$646b253f.getAll(<generated>)
    at com.example.tenant.TenantDataSourceService.getAll(TenantDataSourceService.java:39)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416)
Caused by: org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.orm.hibernate5.SpringSessionContext.currentSession(SpringSessionContext.java:143)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:514)
    at com.example.dao.BaseDao.getSession(BaseDao.java:33)
    at com.example.dao.GenericDao.getAll(GenericDao.java:121)
    at com.example.dao.GenericDao$$FastClassBySpringCGLIB$$a026e92f.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
    at com.example.tenant.TenantDataSourceDao$$EnhancerBySpringCGLIB$$646b253f.getAll(<generated>)
    at com.example.tenant.TenantDataSourceService.getAll(TenantDataSourceService.java:39)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
[2020-05-20 15:32:38,927] [main] [INFO ] [org.springframework.scheduling.concurrent.ExecutorConfigurationSupport.initialize] [user=n/d] - Initializing ExecutorService 'emailThreadPoolTaskExecutor'
[2020-05-20 15:32:39,626] [main] [INFO ] [org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.getOrDeducePassword] [user=n/d] -