这次讨论一下Hibernate的ConnectionProvider接口, 因为我看到某些Hibernate项目是这样配置的:

<property name="c3p0.min_size">5</property>
<property name="c3p0.max_size">30</property>
<property name="c3p0.time_out">1800</property>
<property name="c3p0.max_statement">50</property>

问题是, 这样就配置好了吗? hibernate.connection.provider_class到底需不需要呢? 来看看Hibernate 3.3.2 GA的源码 ConnectionProviderFactory类的newConnectionProvider方法.

public static ConnectionProvider newConnectionProvider(Properties properties, Map connectionProviderInjectionData) throws HibernateException {
    ConnectionProvider connections;
    String providerClass = properties.getProperty(Environment.CONNECTION_PROVIDER);
    if ( providerClass!=null ) {
        try {
            log.info("Initializing connection provider: " + providerClass);
            connections = (ConnectionProvider) ReflectHelper.classForName(providerClass).newInstance();
        }
        catch ( Exception e ) {
            log.error( "Could not instantiate connection provider", e );
            throw new HibernateException("Could not instantiate connection provider: " + providerClass);
        }
    }
    else if ( properties.getProperty(Environment.DATASOURCE)!=null ) {
        connections = new DatasourceConnectionProvider();
    }
    else if ( properties.getProperty(Environment.URL)!=null ) {
        connections = new DriverManagerConnectionProvider();
    }
    else {
        connections = new UserSuppliedConnectionProvider();
    }

    if ( connectionProviderInjectionData != null && connectionProviderInjectionData.size() != 0 ) {
        //inject the data
        try {
            BeanInfo info = Introspector.getBeanInfo( connections.getClass() );
            PropertyDescriptor[] descritors = info.getPropertyDescriptors();
            int size = descritors.length;
            for (int index = 0 ; index < size ; index++) {
                String propertyName = descritors[index].getName();
                if ( connectionProviderInjectionData.containsKey( propertyName ) ) {
                    Method method = descritors[index].getWriteMethod();
                    method.invoke( connections, new Object[] { connectionProviderInjectionData.get( propertyName ) } );
                }
            }
        }
        catch (IntrospectionException e) {
            throw new HibernateException("Unable to inject objects into the conenction provider", e);
        }
        catch (IllegalAccessException e) {
            throw new HibernateException("Unable to inject objects into the conenction provider", e);
        }
        catch (InvocationTargetException e) {
            throw new HibernateException("Unable to inject objects into the conenction provider", e);
        }
    }
    connections.configure(properties);
    return connections;
    }

上面的代码有点长, 精简出核心部分:

ConnectionProvider connections;
String providerClass = properties.getProperty(Environment.CONNECTION_PROVIDER);
if ( providerClass!=null ) {
    connections = (ConnectionProvider) ReflectHelper.classForName(providerClass).newInstance();
}else if ( properties.getProperty(Environment.DATASOURCE)!=null ) {
    connections = new DatasourceConnectionProvider();
}else if ( properties.getProperty(Environment.URL)!=null ) {
    connections = new DriverManagerConnectionProvider();
}else {
    connections = new UserSuppliedConnectionProvider();
}
/**
Environment.CONNECTION_PROVIDER 的定义:
public static final String CONNECTION_PROVIDER ="hibernate.connection.provider_class";
Environment.DATASOURCE 的定义:
public static final String DATASOURCE ="hibernate.connection.datasource";
Environment.URL 的定义:
public static final String URL ="hibernate.connection.url";
*/

可以看到, 如果hibernate.connection.provider_class和hibernate.connection.datasource都没有定义,就会使用内置的连接池,OK,那继续看默认的连接池DriverManagerConnectionProvider,只贴精华部分:

/*连接池就是一个ArrayList !!*/
private final ArrayList pool = new ArrayList();
/*获取连接*/
public Connection getConnection() throws SQLException {
    synchronized (pool) {
        if ( !pool.isEmpty() ) {
            int last = pool.size() - 1;
            Connection pooled = (Connection) pool.remove(last);
            if (isolation!=null) pooled.setTransactionIsolation( isolation.intValue() );
            if ( pooled.getAutoCommit()!=autocommit ) pooled.setAutoCommit(autocommit);
            return pooled;
        }
    }

    log.debug("opening new JDBC connection");
    Connection conn = DriverManager.getConnection(url, connectionProps);
    return conn;
}
/*释放连接*/
public void closeConnection(Connection conn) throws SQLException {
    synchronized (pool) {
        int currentSize = pool.size();
        if ( currentSize < poolSize ) {
            pool.add(conn);
            return;
        }
    }
    conn.close();
}

用一个简单ArrayList做出来的默认连接池,就是这样简单!!! sorry,是简陋!!! 无比简陋!! 性能能有多好?! 你的Hibernate还在用默认连接池? 你还没有配hibernate.connection.provider_class属性? 快去看看吧!!



blog comments powered by Disqus

Published

2011-01-28 14:28:12

Categories


Tags

Fork me on GitHub