Setting up a MultiTenantConnectionProvider using Hibernate 4.2 and Spring 3.1.1

前端 未结 5 1176
长发绾君心
长发绾君心 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 16:39

    Using these guys' responses and this link, I put this together without Spring or anything else but C3P0.

    I had to add these 2 properties to my hibernate config

    properties.setProperty("hibernate.multiTenancy", "SCHEMA");
    properties.setProperty("hibernate.multi_tenant_connection_provider", MultiTenantConnectionProviderImpl.class.getName());
    

    HibernateUtils.java

    import org.hibernate.HibernateException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.service.ServiceRegistry;
    import org.hibernate.service.ServiceRegistryBuilder;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     *
     * @author Alex
     */
    public class HibernateUtils {
        private static final Logger logger = LoggerFactory.getLogger(HibernateUtils.class);
        private static SessionFactory sessionFactory;
    
        static{
            init();
        }
    
        public static void init(){
            try {
                Configuration configuration = new Configuration()
                        .setProperties(ConnectionPropertiesUtils.getProperties());
    
                ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
                sessionFactory = configuration.buildSessionFactory(serviceRegistry);
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        }
    
        public static Session getTenantSession(String tenant){
            return getSession(tenant);
        }
    
        public static Session getAuthSession(){
            return getSession("AUTH");
        }
    
        public static Session getLogSession(){
            return getSession("LOG");
        }
    
        public static Session getConfigSession(){
            return getSession("CONFIG");
        }
    
        public static Session getSession(String tenant)
                throws HibernateException {
            if(sessionFactory == null){
                init();
            }
            return sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
        }
    
        @Deprecated
        public static Session getSession()
                throws HibernateException {
            if(sessionFactory == null){
                init();
            }
            return sessionFactory.openSession();
        }
    }
    

    And MultiTenantConnectionProviderImpl.java

    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import java.beans.PropertyVetoException;
    import java.sql.Connection;
    import java.sql.SQLException;
    import org.hibernate.HibernateException;
    import org.hibernate.service.UnknownUnwrapTypeException;
    import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
    import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
    import org.hibernate.service.spi.Stoppable;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * Simplistic implementation for illustration purposes showing a single
     * connection pool used to serve multiple schemas using "connection altering".
     * Here we use the T-SQL specific USE command; Oracle users might use the ALTER
     * SESSION SET SCHEMA command; etc.
     */
    public class MultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider, Stoppable {
    
        private static Logger log = LoggerFactory.getLogger(MultiTenantConnectionProviderImpl.class);
        private ComboPooledDataSource cpds;
    
        public MultiTenantConnectionProviderImpl() throws PropertyVetoException {
            log.info("Initializing Connection Pool!");
    
            cpds = new ComboPooledDataSource("Example");
            cpds.setDriverClass(ConnectionPropertiesUtils.getProperty("hibernate.connection.driver_class"));
            cpds.setJdbcUrl(ConnectionPropertiesUtils.getProperty("hibernate.connection.url"));
            cpds.setUser(ConnectionPropertiesUtils.getProperty("hibernate.connection.username"));
            cpds.setPassword(ConnectionPropertiesUtils.getProperty("hibernate.connection.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 {
            final Connection connection = getAnyConnection();
            try {
                //This is DB specific syntax. This work for MSSQL and MySQL
                //Oracle uses the ALTER SESSION SET SCHEMA command
                connection.createStatement().execute("USE " + tenantIdentifier);
            } catch (SQLException e) {
                throw new HibernateException("Could not alter JDBC connection to specified schema [" + tenantIdentifier + "]", e);
            }
            return connection;
        }
    
        @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);
            }
        }
    
        public void stop() {
            cpds.close();
        }
    }
    

提交回复
热议问题