我目前正在实施多租户Web应用程序,其中一些后台任务由计时器或Quartz作业运行。
为此,我使用Hibernate 4 multitenant features并使用基于模式的策略。通过在我的MultiTenantConnectionProvider实现中调用以下内容来进行模式切换:
connection.createStatement().execute("SET search_path TO '" + tenantIdentifier + "'");
问题仅在Quartz Job执行时出现,TimerTask下的相同代码没有任何问题。由于一些很好的理由,我想使用Quartz over Timer(持久性,错误处理,触发功能)。
当一个作业迭代到租户列表并在新事务中运行查询时,查询有时会为每个租户返回正确的值,有时会返回另一个租户的值。
我在Hibernate和Spring中启用了TRACE日志级别,我可以看到为每个租户打开会话。
我还跟踪数据库日志中执行的语句,显然出现了问题。这是一个好的执行:
SET search_path TO public
SET search_path TO 'tenantA'
BEGIN
/* criteria query */
select * from TABLE1_ this_ where this_.published_=
= 't'
/* load one-to-many */
select * from TABLE2_ where id_table1_=
= '1234'
COMMIT
SET search_path TO public
SET search_path TO 'tenantB'
BEGIN
/* criteria query */
select * from TABLE1_ this_ where this_.published_=
= 't'
/* load one-to-many */
select * from TABLE2_ where id_table1_=
= '5678'
/* load collection */
select * from TABLE3_ where id_table2_=
= '9876'
COMMIT
SET search_path TO public
当问题出现时,这是相同的执行:
SET search_path TO public
SET search_path TO 'tenantA'
BEGIN
/* criteria query */
select * from TABLE1_ this_ where this_.published_=
= 't'
/* load one-to-many */
select * from TABLE2_ where id_table1_=
= '5678'
/* load collection */
select * from TABLE3_ where id_table2_=
= '9876'
COMMIT
SET search_path TO public
SET search_path TO 'tenantB'
BEGIN
/* criteria query */
select * from TABLE1_ this_ where this_.published_=
= 't'
/* load one-to-many */
select * from TABLE2_ where id_table1_=
= '1234'
COMMIT
SET search_path TO public
在这种情况下,交换查询,而在其他情况下,对两个租户执行相同的查询。在分析数据库日志时,似乎sessionid对于相同的查询是相同的。
三次检查我自己,我在事务中打印SHOW search_path;
的结果,并且它总是返回正确的路径。
同样,当代码在TimerTask中运行时,此行为不存在。
有什么想法吗?我意识到,如果您没有经历过自己,这是一个很难理解的复杂问题。但这就是我所希望的,有人已经通过了同样的事情并且能够对此事有所了解。 如果需要,我可以提供进一步的信息,但现在我认为足以说明问题。
环境:
答案 0 :(得分:0)
好的解决方案找到了。不是Hibernate Multi Tenancy问题。我尝试实现自己的数据源代理机制,问题仍然存在。也没有石英问题,即使是我之前报告的在这种情况下发生的问题,也是众多问题之一。在完全禁用Quartz之后,其他问题以同样的不规则和随机方式上升。
解决方案:使用PostgresSQL 9.3。
为什么呢?不知道。阅读更改日志已经失去了一些时间,但经过几天的努力,我有很多要赶上来。如果有人有线索,请分享。