1

我们使用 Spring 3.2.0 和 Hibernate 4.1.12 开发 Web 应用程序。

该应用程序支持“基于数据源”的多租户,这意味着每个应用程序租户都使用一个专用的数据源。

数据源 JNDI 名称在运行时根据请求应用程序的用户名(用户名说明必须使用哪个租户)解析。解析是实现了Hibernate的org.hibernate.service.jdbc.connections.spi.ConnectionProvider接口。

Spring 配置(摘录)是:

<bean id="tenantHibernateSessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

    <property name="packagesToScan">
        <list>
            <value>com.foo.bar.model</value>
        </list>
    </property>

    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.show_sql">false</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.DB2Dialect</prop>
            <prop key="hibernate.format_sql">false</prop>
            <prop key="hibernate.connection.autocommit">true</prop>
            <prop key="hibernate.connection.provider_class">com.foo.bar.dao.hibernate.CustomConnectionProvider</prop>
        </props>
    </property>
</bean>

在应用程序部署期间,Spring 初始化应用程序和 org.springframework.orm.hibernate4.LocalSessionFactoryBean 实例。这最终会执行数据库访问。此数据库访问失败,因为我们的 CustomConnectionProvider 返回一个空连接。我们返回一个空连接,因为在部署时,我们无法识别当前租户。在应用程序部署期间访问数据库毫无意义。我们得到的堆栈跟踪是:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tenantHibernateSessionFactory' defined in file [D:\Work\Java\apache-tomcat-6.0.39\webapps\ams-gate\WEB-INF\classes\META-INF\spring\persistence.xml]: Invocation of init method failed; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1486)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:873)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:815)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:730)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:558)
    ... 129 more
Caused by: java.lang.NullPointerException
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:119)
    at org.hibernate.service.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:75)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:159)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:131)
    at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:77)
    at org.hibernate.cfg.Configuration.buildSettingsInternal(Configuration.java:2287)
    at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2283)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1752)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1792)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.java:242)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:372)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:357)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1483)
    ... 139 more

我查看了 Hibernate 源代码,发现了一个可以在部署期间禁用数据库访问的属性:

<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>

但它似乎在这里不起作用。

更新 1:这个 Hibernate 属性确实在应用程序部署期间禁用了数据库访问。但是根据 Hibernate 4.1.12 中的 org.hibernate.engine.jdbc.internal.JdbcServicesImpl,这个属性是一个未记录的临时魔法值。

是否有推荐的方法在部署期间禁用数据库访问以正确支持多租户?

感谢您的时间

4

0 回答 0