Hibernate Spring boot 2多租户配置不使用事务
我有一个SpringBoot2应用程序运行良好。我引入了多租户配置,现在它不再工作了 我举了一个例子: 注意:我使用的是HibernateTrasactionMaanger,但是,在我的研究过程中,如果您使用: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
<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] -