我们正在开发一个多租户应用程序,每个租户都有单独的架构。
我们每个架构都使用一个
SessionFactory
,无需使用 OpenSessionInViewFilter
即可正常工作。
我们希望将 Spring
TransactionManager
与 OpenSessionInViewFilter
一起使用。
我们可以找到一些参考来自定义 OpenSessionInViewFilter 来处理多个
SessionFactories
(通过覆盖 lookupSessionFactory
方法),但它对我们不起作用,因为我们需要从 DAO 引用此 Filter。
因此,我们计划使用
OpenSessionInViewInterceptor
,它可以从其他 spring beans (DAO) 访问,但没有找到一种方法来自定义它以基于 TenantId 查找 SessionFactory
。
我们使用 Hibernate 3.2.5 和 Spring-2.5.6
要访问 DAO 中的过滤器,您可以将过滤器定义为 bean 并使用
DelegatingFilterProxy
将此 bean 注册为过滤器:
bean定义:
<bean id="openEntityManagerInViewFilter" class="org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter">
<property name="entityManagerFactoryBeanName" value="entityManagerFactory"/>
</bean>
web.xml 部分:
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
我正在按照你说的做,而且有效。我在 dao 中有 2 个会话工厂(对我来说:主数据库和副本)。自定义 OSIV 过滤器(扩展 spring OpenSessionInViewFilter),并重载
lookupSessionFactory
。我可以确定使用哪个会话工厂,甚至可以基于 url 端点路径。
确保所有 dao 调用都使用与 OSIV 打开会话的会话工厂相匹配的会话工厂。您可以在
OpenSessionInViewFilter.openSession
和 SessionFactoryImpl.getCurrentSession
中设置断点,并确保 SessionFactory
指针 ID 匹配。
我发现
@Transactional
注释不需要指定备用transactionManager。
我设置了web.xml:
<filter>
<description></description>
<display-name>hibernateSessionFilter</display-name>
<filter-name>hibernateSessionFilter</filter-name>
<filter-class>com.companyname.dao.impl.CustomOpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateSessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
CustomOpenSessionInViewFilter
扩展 OpenSessionInViewFilter
并重载 lookupSessionFactory(request)
。它返回SessionFactory
。
我的 applicationContext.xml 有第二组 bean:dataSource、sessionFactory 和 transactionManager。 2 个会话工厂被注入到 dao 基类中。
这 2 个会话工厂的目的是向副本发送一些只读流量,以减少主数据库的负载。
Spring使用
SpringSessionContext
(有一些*SessionContext类可以使用)并且具有与事务同步的逻辑。 SessionFactory.getCurrentSession()
致电 SpringSessionContext.currentSession()
。 TransactionSynchronizationManager
使用静态线程局部来存储状态。
我还在
Transactional
中找到了一个断点,它告诉我事务管理器名称和 Transactional
注释所在的方法。 (TransactionAspectSupport
:345)(也尝试断点TransactionInterceptor
并查看调用堆栈)