1

我在使用 GlassFish 3.1.2 作为 Java EE 容器使用 Hibernate 4.1.7 和 EJB 3.1 实现多租户应用程序时遇到问题 目前有一个实现 org.hibernate.context.spi.CurrentTenantIdentifierResolver 的类,它标识登录的租户获取使用此代码登录的用户:

@Override
public String resolveCurrentTenantIdentifier() {
    try {
        SessionContext context = ServiceLocator.locate(SessionEjbContext.class).getSessionContext();

        String userName = context.getCallerPrincipal().getName();

        AppLogger.info("current tenant identifier [" + userName + "]");

        return userName;
    } catch (Throwable e) {
        AppLogger.info("erro lookup");
    }

    return "default";
}

SessionContext.class 是这样实现的

@Stateful
@SessionScoped
public class SessionEjbContext {

    @Resource
    private SessionContext sessionContext;

    public SessionContext getSessionContext() {
        return sessionContext;
    }
}

然后将 id 提供给扩展 org.hibernate.service.jdbc.connections.spi.AbstractMultiTenantConnectionProvider 的类,该类实现 ConnectionProvider selectConnectionProvider(String tenantIdentifier) 方法,并且必须返回一个 c3p0 ConnectionProvider 对象才能使用。

真正的问题是:当用户 user1 对系统进行身份验证时,db 连接正常。但是当 user2 进行身份验证时,ConnectionProvider selectConnectionProvider(String tenantIdentifier) 方法接收的参数是 user1,而不是 user2,导致我们选择与 user1 相同的数据库。

EntityManager 是使用 PersistenceContextType.EXTENDED 注释实现的,这会导致问题吗?也许它正在重用有关第一个用户的信息!

4

1 回答 1

0

根据各种帖子,对有状态 bean 的 JNDI 查找可以创建 bean 的新实例。相反,为调用resolveCurrentTenantIdentifier() 返回相同的bean。请检查服务定位器和 JNDI 查找方法。JNDI 库缓存对象实例是一种常见的行为。正如您调用 JNDI 查找对应于 user1 的 SessionEjbContext 一样,它可能已被缓存并为所有后续调用返回。

于 2014-02-04T07:01:48.103 回答