使用Hibernate 4.2和Spring 3.1.1设置MultiTenantConnectionProvider [英] Setting up a MultiTenantConnectionProvider using Hibernate 4.2 and Spring 3.1.1

查看:188
本文介绍了使用Hibernate 4.2和Spring 3.1.1设置MultiTenantConnectionProvider的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试使用单独的Schema aproach来设置Hibernate以实现多租户。

现在我已经使用了大约2天的时间并浏览了几乎所有可以通过Google找到的源代码,得到相当沮丧。

Basicaly我试图按照Hibernate提供的指南devguide http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html_single/#d5e4691

但不幸的是,我无法找到ConnectionProviderUtils来构建ConnectionProvider。
目前我想弄清楚2点:$ b​​
$ b


  1. 为什么我的MSSQLMultiTenantConnectionProvider的配置(Properties props)方法永远不会被调用。从我从不同的其他ConnectionProvider实现的源代码和描述中解释我假设这个方法将被调用来初始化ConnectionProvider。由于我无法使用configure(Properties props),所以我尝试了其他方法来获取应用程序Context中指定的hibernate属性和DataSource和hibernate.cfg.xml。 (比如将数据源直接注入到ConnectionProvider中)


任何可能的解决方法的指针(方法,类,教程)

所以这里是我的实现的相关部分:

数据源和Hibernate.cfg.xml:

 < bean id =dataSourceclass =org.springframework.jdbc.datasource.DriverManagerDataSource> 
< property name =driverClassNamevalue =com.microsoft.sqlserver.jdbc.SQLServerDriver/>
< property name =urlvalue =jdbc:sqlserver://< host>:< port> ;; databaseName =< DbName> ;; />
< property name =passwordvalue =< password> />
< / bean>
< bean id =sessionFactoryclass =org.springframework.orm.hibernate4.LocalSessionFactoryBean>
<! - 属性名称=dataSourceref =dataSource/ - >
< property name =annotatedClasses>
< list>
<值> c.h.utils.hibernate.User< /值>
<值> c.h.utils.hibernate.Role< /值>
<值> c.h.utils.hibernate.Tenant< /值>
< / list>
< / property>
< property name =hibernateProperties>
<值>
hibernate.dialect = org.hibernate.dialect.SQLServerDialect
hibernate.show_sql = true
hibernate.multiTenancy = SCHEMA
hibernate.tenant_identifier_resolver = chutils.hibernate.CurrentTenantIdentifierResolver
hibernate.multi_tenant_connection_provider = chutils.hibernate.MSSQLMultiTenantConnectionProviderImpl
< / value>
< / property>
< / bean>

MSSQLMultiTenantConnectionProviderImpl:

  package c.hoell.utils.hibernate; 

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.hibernate.service.UnknownUnwrapTypeException;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
导入org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MSSQLMultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider {




private static final long serialVersionUID = 8074002161278796379L;

@Autowired
私有DataSource数据源;

$ b $ public void configure(Properties props)throws HibernateException {

}


@Override
public连接getAnyConnection()抛出SQLException {
属性properties = getConnectionProperties(); //设置hibernate属性的方法

DriverManagerConnectionProviderImpl defaultProvider = new DriverManagerConnectionProviderImpl();
defaultProvider.configure(properties);
Connection con = defaultProvider.getConnection();
ResultSet rs = con.createStatement()。executeQuery(SELECT * FROM [schema] .table);
rs.close(); //声明和sql只是测试连接
return defaultProvider.getConnection();
}

@Override
public Connection getConnection(String tenantIdentifier)throws SQLException {
< - 不知道如何实现 - >
}

@Override
public void releaseAnyConnection(Connection connection)throws SQLException {
connection.close();


@Override
public void releaseConnection(String tenantIdentifier,Connection connection){
try {
this.releaseAnyConnection(connection) ;
} catch(SQLException e){
// TODO自动生成的catch块
e.printStackTrace();
}
}

@Override
public boolean supportsAggressiveRelease(){
return false;
}

@Override
public boolean isUnwrappableAs(Class unwrapType){
return ConnectionProvider.class.equals(unwrapType)|| MultiTenantConnectionProvider.class.equals(unwrapType)|| MSSQLMultiTenantConnectionProviderImpl.class.isAssignableFrom(unwrapType);
}

@SuppressWarnings(unchecked)
@Override
public< T> T unwrap(Class< T> unwrapType){
if(isUnwrappableAs(unwrapType)){
return(T)this;
}
else {
throw new UnknownUnwrapTypeException(unwrapType);
}
}

public DataSource getDataSource(){
return dataSource;
}

public void setDataSource(DataSource dataSource){
this.dataSource = dataSource;
}

}

现在有两种可能的方法我看到从配置文件中获得我需要的配置。要么运行configure()方法,要么以某种方式使DataSource的注入成为可能。
我猜第一个是更好的方法。



重要的一点是,我只让一个租户使用Hibernate(意味着没有使用MultiTenantConnectionProvider,使用Hibernate使用的标准ConnectionProvider)

非常感谢任何阅读这篇文章的人。期待答案。



最好的祝愿

更新1: b
$ b

我已经玩了一下,并将connectiondetails硬编码到我的MultiTenantConnectionProvider(更新了上面的代码)。这对于MultiTenantConnectionProvider来说工作正常。但是这仍然不能解决我的问题。
现在,我的应用程序在初始化事务管理器时失败:

 < tx:annotation -driven transaction-manager =txManagerproxy-target-class =true/> 
< bean id =txManagerclass =org.springframework.orm.hibernate4.HibernateTransactionManager>
< property name =sessionFactoryref =sessionFactory/>
< / bean>

这是异常堆栈跟踪的顶部:


引起:java.lang.NullPointerException在
org.springframework.orm.hibernate4.SessionFactoryUtils.getDataSource(SessionFactoryUtils.java:101)
at
org.springframework.orm.hibernate4.HibernateTransactionManager.afterPropertiesSet(HibernateTransactionManager.java:264)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory。
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)

我在调试模式下追踪了这个问题,发现问题在于我的SessionFactory在某种程度上没有掌握DataSource。 (我是否在hibernate.cfg.xml中指定了DataSource没有区别)
但是当初始化TransactionManager时,它试图从SessionFactory获取DataSource,并因此导致NullPointerException异常。
有没有人提示hibernate的内部工作点在失败?在我看到的所有文档和帖子中,没有任何迹象表明我需要处理向SessionFactory注入DataSource。
现在我想我试图弄清楚如何获得一个DataSource到需要的地方或者如何改变初始化流程。如果有人有一个更好的主意,我会非常高兴。



编辑:现在在Hibernate Forums上发布:

更新2:



所以我设法通过设置autodetectDataSource属性解决此问题TransactionManager为false:

 < property name =autodetectDataSourcevalue =false/> 

我从下面的帖子得到了这个提示 http://forum.springsource.org/showthread.php?123478-会话工厂配置的换多租户 - 丁没有租户标识符指定。不幸的是,我现在陷入了这个问题。 ^^但是这是另一个话题的问题(编辑:原来这只是从早期的测试+一个旧的依赖关系错误配置)



至于这个话题,问题仍然是我想以某种方式重新使用DataSource,我已经在配置中使用了Spring Security,因此Hibernate可以避免在两个地方配置DataSource。
所以问题仍然是如何在我的MultiTenantConnectionProvider中集成DataSource的使用。有没有人有一个想法,在哪里可以找到任何提示? 解决方案

确定要包装它,下面是我最终得到的以下内容:我使用一个简单的CurrentTenantIdentifierResolver。而不是试图将DataSource从其他位置注入到MultiTenantConnectionProviderImpl中,我创建了DataSource(c3p0 ComboPooledDatasource) ConnectionProvider并开始仅使用my提供的连接ConnectionProvider等。所以我消除了额外的数据源。为了使DataSource的属性易于配置,我选择从属性文件中获取配置数据。


$ b

CurrentTenantIdentifierResolverImpl:

  public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {

$ b $ / **
*该方法返回RequestServerName作为tenantidentifier。
*如果不存在FacesContext,则返回null。
*
* @return String tenantIdentifier
* /
@Override
public String resolveCurrentTenantIdentifier(){
if(FacesContext.getCurrentInstance()!= null ){
返回FacesContext.getCurrentInstance()。getExternalContext()。getRequestServerName();
} else {
return null;

}

@Override
public boolean validateExistingCurrentSessions(){
return true;




$ b

MultiTenantConnectionProviderImpl:请注意,PropertyUtil只是一个简单的本地帮助类来获取我的属性。因为它没什么特别之处,所以我不会将它包含在内以免混淆答案。

  public class MultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider {


private static final long serialVersionUID = 8074002161278796379L;


private static Logger log = LoggerFactory.getLogger(MultiTenantConnectionProviderImpl.class);

私人ComboPooledDataSource cpds;

私有属性属性;

/ **
*
*构造函数。基于config.properties初始化ComboPooledDataSource。
*
* @throws PropertyVetoException
* /
public MultiTenantConnectionProviderImpl()throws PropertyVetoException {
log.info(Initializing Connection Pool!);
properties = new Properties();
try {
properties.load(Thread.currentThread()。getContextClassLoader()。getResourceAsStream(config.properties));
} catch(IOException e){
throw new RuntimeException(e);
}
cpds = new ComboPooledDataSource(Example);
cpds.setDriverClass(properties.getProperty(jdbc.driver));
cpds.setJdbcUrl(properties.getProperty(jdbc.url));
cpds.setUser(properties.getProperty(jdbc.user));
cpds.setPassword(PropertyUtil.getCredential(jdbc.password));
log.info(连接池初始化!);


$ b @Override
public Connection getAnyConnection()throws SQLException {
log.debug(获取默认连接:::连接数max):busy - idle):{}:{} - {},new int [] {cpds.getMaxPoolSize(),cpds.getNumBusyConnectionsAllUsers(),cpds.getNumIdleConnectionsAllUsers()});
if(cpds.getNumConnectionsAllUsers()== cpds.getMaxPoolSize()){
log.warn(打开的最大连接数);

if(cpds.getNumConnectionsAllUsers()== cpds.getMaxPoolSize()&& cpds.getNumIdleConnectionsAllUsers()== 0){
log.error(Connection pool empty! );
}
return cpds.getConnection();

$ b @Override
public Connection getConnection(String tenantIdentifier)throws SQLException {
log.debug(Get {} Connection :::连接数(max :busy - idle):{}:{} - {},new Object [] {tenantIdentifier,cpds.getMaxPoolSize(),cpds.getNumBusyConnectionsAllUsers(),cpds.getNumIdleConnectionsAllUsers()});
if(cpds.getNumConnectionsAllUsers()== cpds.getMaxPoolSize()){
log.warn(打开的最大连接数);

if(cpds.getNumConnectionsAllUsers()== cpds.getMaxPoolSize()&& cpds.getNumIdleConnectionsAllUsers()== 0){
log.error(Connection pool empty! );
}
返回cpds.getConnection(tenantIdentifier,PropertyUtil.getCredential(tenantIdentifier));
}

@Override
public void releaseAnyConnection(Connection connection)throws SQLException {
connection.close();

$ b @Override
public void releaseConnection(String tenantIdentifier,Connection connection){
try {
this.releaseAnyConnection(connection);
} catch(SQLException e){
抛出new RuntimeException(e);
}
}

@Override
public boolean supportsAggressiveRelease(){
return false;
}

@SuppressWarnings(rawtypes)
@Override
public boolean isUnwrappableAs(Class unwrapType){
return ConnectionProvider.class.equals(unwrapType )|| MultiTenantConnectionProvider.class.equals(unwrapType)|| MultiTenantConnectionProviderImpl.class.isAssignableFrom(unwrapType);
}

@SuppressWarnings(unchecked)
@Override
public< T> T unwrap(Class< T> unwrapType){
if(isUnwrappableAs(unwrapType)){
return(T)this;
}
else {
throw new UnknownUnwrapTypeException(unwrapType);


$ b $ / code $ / pre

c3p0特定配置来自 c3p0-config.xml

 < c3p0-config> 
< named-config name =示例>
< property name =acquireIncrement> 3< / property>
< property name =preferredTestQuery> SELECT 1< / property>
< property name =checkoutTimeout> 2000< / property>
< property name =idleConnectionTestPeriod> 30< / property>
< property name =initialPoolSize> 1< / property>
< property name =maxIdleTime> 18000< / property>
< property name =maxPoolSize> 30< / property>
< property name =minPoolSize> 1< / property>
< property name =maxStatements> 50< / property>
< property name =testConnectionOnCheckin> true< / property>
< / named-config>
< / c3p0-config>

特定于db的属性由 config.properties 文件提供:

  jdbc.url =< serverUrl> 
jdbc.driver =< driverClass>
jdbc.dbName =< dBname>
jdbc.dbowner =< dbo>
jdbc.username =< user>
jdbc.password =<密码>

hibernate.dialect =< hibernateDialect>
hibernate.debug = false

凭证以与其他文件类似的方式获取。



提供改进的任何反馈意见。

I am currently trying to set up Hibernate for multi tenancy using the seperate Schema aproach.
After working on it for about 2 days now and browsing nearly every source I could find via Google I am starting to get quite frustrated.

Basicaly I am trying to follow the guide provided in the Hibernate devguide http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html_single/#d5e4691
But unfortunately I am not able to find the ConnectionProviderUtils to build the ConnectionProvider. Currently I am trying to figure out 2 Points:

  1. Why the configure(Properties props) method of my MSSQLMultiTenantConnectionProvider is never called. From what I interpreted from the source of and description of different other ConnectionProvider implementions I am assuming this method is going to be called to initialize the ConnectionProvider.

  2. Since I am not able to work with the configure(Properties props) I tried out other approaches of somehow obtaining the hibernate properties and DataSource specified in the application Context and the hibernate.cfg.xml. (Like injecting the datasource directly into the ConnectionProvider)

Any pointers to possible ways to solve this (Methods, Classes, Tutorials)

So here are the relevant parts of my implementation:
Data Source and Hibernate.cfg.xml:

    <bean id="dataSource"   class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
        <property name="url" value="jdbc:sqlserver://<host>:<port>;databaseName=<DbName>;" />
        <property name="username" value=<username> />
        <property name="password" value=<password> />
   </bean>
   <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <!-- property name="dataSource" ref="dataSource" /-->
        <property name="annotatedClasses">
            <list>
                <value>c.h.utils.hibernate.User</value>
                <value>c.h.utils.hibernate.Role</value>
                <value>c.h.utils.hibernate.Tenant</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <value>
                hibernate.dialect=org.hibernate.dialect.SQLServerDialect
                hibernate.show_sql=true
                hibernate.multiTenancy=SCHEMA
                hibernate.tenant_identifier_resolver=c.h.utils.hibernate.CurrentTenantIdentifierResolver
                hibernate.multi_tenant_connection_provider=c.h.utils.hibernate.MSSQLMultiTenantConnectionProviderImpl 
            </value>
        </property>
    </bean>

MSSQLMultiTenantConnectionProviderImpl:

package c.hoell.utils.hibernate;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.hibernate.service.UnknownUnwrapTypeException;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MSSQLMultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider  {




    private static final long serialVersionUID = 8074002161278796379L;

    @Autowired
    private DataSource dataSource;


    public void configure(Properties props) throws HibernateException {

    }


    @Override
    public Connection getAnyConnection() throws SQLException {
        Properties properties = getConnectionProperties(); //method which sets the hibernate properties

        DriverManagerConnectionProviderImpl defaultProvider = new   DriverManagerConnectionProviderImpl();
        defaultProvider.configure(properties);
        Connection con = defaultProvider.getConnection();
        ResultSet rs = con.createStatement().executeQuery("SELECT * FROM [schema].table");
        rs.close(); //the statement and sql is just to test the connection
        return defaultProvider.getConnection();
    }

    @Override
    public Connection getConnection(String tenantIdentifier) throws SQLException {
        <--not sure how to implement this-->
    }

    @Override
    public void releaseAnyConnection(Connection connection) throws SQLException {
        connection.close();

    }

    @Override
    public void releaseConnection(String tenantIdentifier, Connection connection){
        try {
            this.releaseAnyConnection(connection);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public boolean supportsAggressiveRelease() {
        return false;
    }

    @Override
    public boolean isUnwrappableAs(Class unwrapType) {
        return ConnectionProvider.class.equals( unwrapType ) || MultiTenantConnectionProvider.class.equals( unwrapType ) || MSSQLMultiTenantConnectionProviderImpl.class.isAssignableFrom( unwrapType );
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T unwrap(Class<T> unwrapType) {
        if ( isUnwrappableAs( unwrapType ) ) {
            return (T) this;
        }
        else {
            throw new UnknownUnwrapTypeException( unwrapType );
        }
    }

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

}

Right now there are 2 possible approaches I see to obtaint the configurations i need from the config files. Either get the configure() method to run or somehow make the injection of the DataSource possible. I guess the first one would be the better way.

An important thing to mention is that I had Hibernate up and running for only one tenant (means without using the MultiTenantConnectionProvider, using the standard ConnectionProvider used by Hibernate)

Already a big thanks to anyone who is reading this post. Looking forward to the answers.

Best regards

Update 1:

I have played around with this a bit and hardcoded the connectiondetails into my MultiTenantConnectionProvider (updated the Code above). This is working fine in regards to the MultiTenantConnectionProvider. But this is still not solving my problems. Now my Application fails at initializing the Transaction Manager:

<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
    <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

This is the top of the exception stacktrace:

Caused by: java.lang.NullPointerException at org.springframework.orm.hibernate4.SessionFactoryUtils.getDataSource(SessionFactoryUtils.java:101) at org.springframework.orm.hibernate4.HibernateTransactionManager.afterPropertiesSet(HibernateTransactionManager.java:264) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)

I traced this issue down in debug mode and found out that the problem is that my SessionFactory is somehow not getting hold of the DataSource. (It makes no difference whether I specify the DataSource in the hibernate.cfg.xml or not) But when initializing the TransactionManager it tries to get the DataSource from the SessionFactory and fails with a NullPointerException as a result. Does anyone have an hint at what point of the inner workings of hibernate this is failing? In all the documentation and posts I have seen there was no indication that I need to handle the injection of the DataSource into the SessionFactory. For now I just guess I try to figure out how to get a DataSource into the needed place or how to change the initializing flow. If anyone has a better idea I would be really happy.

Edit: Also posted this in the Hibernate Forums now:

Update 2:

So I managed to get around this issue by setting the autodetectDataSource property in the TransactionManager to false:

<property name="autodetectDataSource" value="false"/>

I got this hint from the following post http://forum.springsource.org/showthread.php?123478-SessionFactory-configured-for-multi-tenancy-but-no-tenant-identifier-specified. Unfortunately I am now stuck at exactly that issue. ^^" But this is a problem for another topic. (Edit: Turns out this was only misconfiguration from earlier testing + one old dependency)

As for this topic the problem remains that I want to somehow be able to reuse the DataSource, which I already have in the configuration for the use of Spring Security anyway, for Hibernate to avoid the need for having to configure the DataSource in two places. So the question still stands how to integrate the use of the DataSource in my MultiTenantConnectionProvider. Does anyone have an idea on where to find any hints on that?

解决方案

Ok to wrap this up, here is what I ended up with the following. I use a simple CurrentTenantIdentifierResolver. And Instead of trying to inject the DataSource from somewhere else to my MultiTenantConnectionProviderImpl I create the DataSource (c3p0 ComboPooledDatasource) in the ConnectionProvider and started using only the connections provided by the my ConnectionProvider. So I eliminated the extra DataSource. To make the properties of the DataSource easily configurable I opted to get the configuration data from a properties file.

CurrentTenantIdentifierResolverImpl:

public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {


    /**
     * The method returns the RequestServerName as tenantidentifier.
     * If no FacesContext is available null is returned.
     * 
     * @return String tenantIdentifier
     */
    @Override
    public String resolveCurrentTenantIdentifier() {
        if (FacesContext.getCurrentInstance() != null){
            return FacesContext.getCurrentInstance().getExternalContext().getRequestServerName();
        } else {
            return null;
        }
    }

    @Override
    public boolean validateExistingCurrentSessions() {
        return true;
    }

}

MultiTenantConnectionProviderImpl:

Note that the PropertyUtil is just a simple local helper class to fetch my properties. Since it is nothing special I won't include it to not clutter the answer.

public class MultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider  {


    private static final long serialVersionUID = 8074002161278796379L;


    private static Logger log = LoggerFactory.getLogger(MultiTenantConnectionProviderImpl.class );

    private ComboPooledDataSource cpds;

    private Properties properties;

    /**
     * 
     * Constructor. Initializes the ComboPooledDataSource based on the config.properties.
     * 
     * @throws PropertyVetoException
     */
    public MultiTenantConnectionProviderImpl() throws PropertyVetoException {
        log.info("Initializing Connection Pool!");
        properties = new Properties();
        try {
            properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        cpds = new ComboPooledDataSource("Example");
        cpds.setDriverClass(properties.getProperty("jdbc.driver"));
        cpds.setJdbcUrl(properties.getProperty("jdbc.url"));
        cpds.setUser(properties.getProperty("jdbc.user"));
        cpds.setPassword(PropertyUtil.getCredential("jdbc.password"));
        log.info("Connection Pool initialised!");
    }


    @Override
    public Connection getAnyConnection() throws SQLException {
        log.debug("Get Default Connection:::Number of connections (max: busy - idle): {} : {} - {}",new int[]{cpds.getMaxPoolSize(),cpds.getNumBusyConnectionsAllUsers(),cpds.getNumIdleConnectionsAllUsers()});
        if (cpds.getNumConnectionsAllUsers() == cpds.getMaxPoolSize()){
            log.warn("Maximum number of connections opened");
        }
        if (cpds.getNumConnectionsAllUsers() == cpds.getMaxPoolSize() && cpds.getNumIdleConnectionsAllUsers()==0){
            log.error("Connection pool empty!");
        }
        return cpds.getConnection();
    }

    @Override
    public Connection getConnection(String tenantIdentifier) throws SQLException {
        log.debug("Get {} Connection:::Number of connections (max: busy - idle): {} : {} - {}",new Object[]{tenantIdentifier, cpds.getMaxPoolSize(),cpds.getNumBusyConnectionsAllUsers(),cpds.getNumIdleConnectionsAllUsers()});
        if (cpds.getNumConnectionsAllUsers() == cpds.getMaxPoolSize()){
            log.warn("Maximum number of connections opened");
        }
        if (cpds.getNumConnectionsAllUsers() == cpds.getMaxPoolSize() && cpds.getNumIdleConnectionsAllUsers()==0){
            log.error("Connection pool empty!");
        }
        return cpds.getConnection(tenantIdentifier, PropertyUtil.getCredential(tenantIdentifier));
    }

    @Override
    public void releaseAnyConnection(Connection connection) throws SQLException {
        connection.close();
    }

    @Override
    public void releaseConnection(String tenantIdentifier, Connection connection){
        try {
            this.releaseAnyConnection(connection);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean supportsAggressiveRelease() {
        return false;
    }

    @SuppressWarnings("rawtypes")
    @Override
    public boolean isUnwrappableAs(Class unwrapType) {
        return ConnectionProvider.class.equals( unwrapType ) || MultiTenantConnectionProvider.class.equals( unwrapType ) || MultiTenantConnectionProviderImpl.class.isAssignableFrom( unwrapType );
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T unwrap(Class<T> unwrapType) {
        if ( isUnwrappableAs( unwrapType ) ) {
            return (T) this;
        }
        else {
            throw new UnknownUnwrapTypeException( unwrapType );
        }
    }
}

The c3p0 specific config is taken from the c3p0-config.xml:

<c3p0-config>
    <named-config name="Example">
        <property name="acquireIncrement">3</property>
        <property name="preferredTestQuery">SELECT 1</property>
        <property name="checkoutTimeout">2000</property>
        <property name="idleConnectionTestPeriod">30</property>
        <property name="initialPoolSize">1</property>
        <property name="maxIdleTime">18000</property>
        <property name="maxPoolSize">30</property>
        <property name="minPoolSize">1</property>
        <property name="maxStatements">50</property>
        <property name="testConnectionOnCheckin">true</property>
    </named-config>
</c3p0-config>

And the db specific properties are provided by a config.properties file:

jdbc.url=<serverUrl>
jdbc.driver=<driverClass>
jdbc.dbName=<dBname>
jdbc.dbowner=<dbo>
jdbc.username=<user>
jdbc.password=<password>

hibernate.dialect=<hibernateDialect>
hibernate.debug=false

The credentials are fetched in a similar fashion from another file.

Any feedback providing improvements is appreciated.

这篇关于使用Hibernate 4.2和Spring 3.1.1设置MultiTenantConnectionProvider的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆