在Hibernate中动态创建SessionFactory

时间:2014-10-02 09:17:48

标签: java database hibernate spring-mvc sessionfactory

在我的应用程序中,每个客户端都有多个数据库。我想根据我的应用程序中登录的客户端访问数据库。

有两种选择:
1)在hibernate-config.xml文件中使用多个SessionFactory条目 2)重复hibernate pojo文件。

但我想在运行时创建所有这些的LocalSessionFactoryBean,SessionFactory,TransactionManager。那我该怎么做呢? 我不想在hibernate-config.xml文件中做多个SessionFactory和DataSource条目。

我在下面尝试过片段。

@Configuration
@EnableTransactionManagement
public class PersistenceHibernateConfig
{

    private String  driverClassName;

    private String  url;

    String          hibernateDialect;

    boolean         hibernateShowSql;

    @Bean
    public LocalSessionFactoryBean alertsSessionFactoryBean()
    {
        final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(this.restDataSource());
        sessionFactory.setPackagesToScan(new String[] { "com.ezdi.cac.bean.table" });
        sessionFactory.setHibernateProperties(this.hibernateProperties());

        return sessionFactory;
    }

    @Bean
    public DataSource restDataSource()
    {
        final DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(this.driverClassName);
        dataSource.setUrl(this.url);
        dataSource.setUsername("root");
        dataSource.setPassword("root");

        return dataSource;
    }

    @Bean
    public HibernateTransactionManager transactionManager()
    {
        final HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(this.alertsSessionFactoryBean().getObject());

        return txManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslationPostProcessor()
    {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    @Bean
    public PersistenceExceptionTranslator exceptionTranslator()
    {
        return new HibernateExceptionTranslator();
    }

    final Properties hibernateProperties()
    {
        return new Properties()
        {
            {
                this.put("persistence.dialect", PersistenceHibernateConfig.this.hibernateDialect);
                this.put("hibernate.show_sql", PersistenceHibernateConfig.this.hibernateShowSql);
            }
        };

    }

    /**
     * @return the driverClassName
     */
    public String getDriverClassName()
    {
        return driverClassName;
    }

    /**
     * @param driverClassName the driverClassName to set
     */
    public void setDriverClassName(String driverClassName)
    {
        this.driverClassName = driverClassName;
    }

    /**
     * @return the url
     */
    public String getUrl()
    {
        return url;
    }

    /**
     * @param url the url to set
     */
    public void setUrl(String url)
    {
        this.url = url;
    }

    /**
     * @return the hibernateDialect
     */
    public String getHibernateDialect()
    {
        return hibernateDialect;
    }

    /**
     * @param hibernateDialect the hibernateDialect to set
     */
    public void setHibernateDialect(String hibernateDialect)
    {
        this.hibernateDialect = hibernateDialect;
    }

    /**
     * @return the hibernateShowSql
     */
    public boolean isHibernateShowSql()
    {
        return hibernateShowSql;
    }

    /**
     * @param hibernateShowSql the hibernateShowSql to set
     */
    public void setHibernateShowSql(boolean hibernateShowSql)
    {
        this.hibernateShowSql = hibernateShowSql;
    }

}

但每当我通过LocalSessionFactoryBean并通过HibernateTransactionManager获取SessionFactory时,我得到它null。我不知道为什么我得到null?

2 个答案:

答案 0 :(得分:3)

您应该了解Hibernate Multi-Tenancy,它是根据此要求量身定制的。从Hibernate 4.x开始,它可用并建议使用而不是使用多个SessionFactory。请仔细阅读post

答案 1 :(得分:0)

以下所有内容仅在Web应用程序中有意义,但由于问题有spring-mvc标记...

假设您有办法从连接的用户名获取数据库名称,并且在用户登录并建立会话之前不访问数据库,您可以简单地将所有内容放在会话范围内。

只需将范围注释添加到相关的bean:

@Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)

使用JDP代理,前提是您通过接口绑定bean(至少对于DataSource和SessionFactory应该是这种情况,如果是正常使用的话,也应该是事务管理器)。如果因为您需要使用类而中断,请使用proxyMode=ScopedProxyMode.TARGET_CLASS

这样,您甚至可以将会话工厂绑定到(单例bean)Dao中,并且由于使用了作用域代理,每个用户都将使用它自己的。

精巧的部分是编写getUrl()方法,因为它必须返回正确的URL。但是您也可以使用会话范围的bean来存储URL并在登录时存储URL。