Setting up a MultiTenantConnectionProvider using Hibernate 4.2 and Spring 3.1.1

前端 未结 5 1172
长发绾君心
长发绾君心 2020-12-04 15:59

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

5条回答
  •  半阙折子戏
    2020-12-04 17:03

    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 unwrap(Class unwrapType) {
            if ( isUnwrappableAs( unwrapType ) ) {
                return (T) this;
            }
            else {
                throw new UnknownUnwrapTypeException( unwrapType );
            }
        }
    }
    

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

    
        
            3
            SELECT 1
            2000
            30
            1
            18000
            30
            1
            50
            true
        
    
    

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

    jdbc.url=
    jdbc.driver=
    jdbc.dbName=
    jdbc.dbowner=
    jdbc.username=
    jdbc.password=
    
    hibernate.dialect=
    hibernate.debug=false
    

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

    Any feedback providing improvements is appreciated.

提交回复
热议问题