4

我想通过自定义MultiTenantConnectionProvider获得Spring-Data JPA与Hibernate一起工作。春季数据JPA与多租户休眠

在我的配置下面的一切似乎工作。每次尝试调用Repository方法时,我的MultiTenantConnectionProviderImpl类都会被调用。

主要问题是没有办法提供租户标识符。 Spring-Data提供的Repository接口负责获取Hibernate Session。

有什么办法可以为Spring-Data提供租户标识符吗?或者是有什么地方我们可以拦截创建休眠会话,所以我们可以适当地调用 sessionFactory.withOptions().tenantIdentifier(itendintifier).openSession();

这是我的Spring配置XML文件。我试图尽可能保持它的骨干。

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context.xsd 
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> 

    <context:annotation-config/> 
    <context:component-scan base-package="com.company"/> 
    <jpa:repositories base-package="com.company.repositories"/> 
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     <property name="packagesToScan" value="com.company.entities"/> 
     <property name="dataSource" ref="dataSource"/> 
     <property name="jpaVendorAdapter"> 
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
       <property name="showSql" value="true"/> 
      </bean> 
     </property> 
    </bean> 


    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
     <property name="sessionFactory" ref="sessionFactory"/> 
    </bean> 

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
     <property name="hibernateProperties"> 
      <props> 
       <prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2012Dialect</prop> 
       <prop key="hibernate.format_sql">true</prop> 
       <prop key="hibernate.multi_tenant_connection_provider">com.company.hibernate.MultiTenantConnectionProviderImpl</prop> 
       <prop key="hibernate.multiTenancy">DATABASE</prop> 
      </props> 
     </property> 
    </bean> 


    <tx:annotation-driven transaction-manager="transactionManager"/> 

    <!--Vendor specific properties here--> 
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
     <property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver"/> 
     <property name="url" value="jdbc:jtds:sqlserver://localhost:1433/myDatabase"/> 
     <property name="username" value="username"/> 
     <property name="password" value="password"/> 
    </bean> 

</beans> 

回答

5

使用CurrentTenantIdentifierResolver

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
    <property name="hibernateProperties"> 
     <map> 
      <entry key="hibernate.dialect" value="org.hibernate.dialect.SQLServer2012Dialect"> 
      <entry key="hibernate.format_sql" value="true"> 
      <entry key="hibernate.multi_tenant_connection_provider" value="com.company.hibernate.MultiTenantConnectionProviderImpl"> 
      <entry key="hibernate.multiTenancy" value="DATABASE"> 
      <!-- tenant resolver as spring bean --> 
      <entry key="hibernate.tenant_identifier_resolver" value-ref="currentTenantIdentifierResolver"/> 
     </map> 
    </property> 
</bean> 

<bean id="currentTenantIdentifierResolver" 
    class="com.xxx.CurrentTenantResolver"> 
</bean> 

简单的承包者标识符解析会是这样的:

public class CurrentTenantResolver implements CurrentTenantIdentifierResolver { 

    public String resolveCurrentTenantIdentifier() { 
     // retrieve tenant from logged in user 
     User usr = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal() ;  
     return usr.getTenantName(); 

    } 

    public boolean validateExistingCurrentSessions() { 
     return true; 
    } 

} 

记住上面的类是一个Spring bean,这样你就可以自动连接任意Spring Bean(服务/道)就像普通的春天豆。

每当春天需要会话时,hibernate将从该bean中检索租户标识符。