数据库连接池DBCP框架的研究以及源代码分析一:第一个DBCP例子

   数据库连接池是在commons-pool的基础上扩展来的,实际上很简单,就是把连接放在池中,以达到连接共享以及避免建立新连接以及关闭连接占用资源,当然,DBCP设计得很精妙,连Statement都可以进行放入池中缓存,研究这框架的代码,确实对我们学习设计很有好处,先来看看连接池怎么用,请看下面代码:


/**
* @param args
* @throws IOException 
*/
public static void main(String[] args)   {
// TODO Auto-generated method stub
Properties prop = new Properties();

 try {
 prop.load(TEST.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"));//加载配置
DataSource dataSource = org.apache.commons.dbcp.BasicDataSourceFactory.createDataSource(prop);//将配置传递给Datasource工厂

Connection conn = dataSource.getConnection();//获取连接
Statement st = conn.createStatement();
String sql = "select * from UserInfo";
ResultSet resultSet = st.executeQuery(sql);
while(resultSet.next()){
System.out.println(resultSet.getString("name"));
}

resultSet .close();

st.close();
conn.close();//注意,这里的连接,并不会真的关闭

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

再来看看配置文件:dbcpconfig.properties


//JDBC相关配置
driverClassName=com.microsoft.jdbc.sqlserver.SQLServerDriver
url=jdbc:sqlserver://localhost:1433;DatabaseName=JDBCTEST
username=sa
password=password
initialSize=10//初始化连接数量大小
maxActive=50//最大连接数
maxIdle=20//最大空闲连接
minIdle=5//最小空闲连接
maxWait=60000//最大等待时间
connectionProperties=useUnicode=true;characterEncoding=utf-8//连接URL的属性
defaultAutoCommit=true//是否自动事务,默认不启动
defaultReadOnly=//是否只读
defaultTransactionIsolation=READ_UNCOMMITTED//数据库隔离界别


就这样,使用起来很简单,我们来看看写的代码:


DataSource dataSource = org.apache.commons.dbcp.BasicDataSourceFactory.createDataSource(prop);


DataSource  是java.sql包里面的一个接口,里面只有一个方法,就是getConnection(),但它继承自 CommonDataSource与Wrap,看类图:






因此,可以猜测到BasicDataSourceFactory创建了一个DataSource类型的对象出来,并利用它来创建Connection接口。先别急于进入代码内部,先看看BasicDataSourceFactory类的实现,先找点蛛丝马迹,对后面整体的把握很有好处,BasicDataSourceFactory的代码如下:

public class BasicDataSourceFactory implements ObjectFactory {

//这些实际是配置文件的内容
    private final static String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";//默认是否自动提交
    private final static String PROP_DEFAULTREADONLY = "defaultReadOnly";//是否只读
    private final static String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";//数据库隔离级别
    private final static String PROP_DEFAULTCATALOG = "defaultCatalog";//数据库名称
    private final static String PROP_DRIVERCLASSNAME = "driverClassName";//驱动程序名称
    private final static String PROP_MAXACTIVE = "maxActive";//最大连接
    private final static String PROP_MAXIDLE = "maxIdle";//最大空闲数
    private final static String PROP_MINIDLE = "minIdle";//最小空闲数
    private final static String PROP_INITIALSIZE = "initialSize";//初始化大小
    private final static String PROP_MAXWAIT = "maxWait";//最大等待时间
    private final static String PROP_TESTONBORROW = "testOnBorrow";//借出对象时是否测试
    private final static String PROP_TESTONRETURN = "testOnReturn";//归还对象时是否测试
    private final static String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";//验证对象的时间间隔
    private final static String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";//每次检测对象个数
    private final static String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis";//空闲时间超过多长就自动断开
    private final static String PROP_TESTWHILEIDLE = "testWhileIdle";//空闲时是否测试对象
    private final static String PROP_PASSWORD = "password";
    private final static String PROP_URL = "url";
    private final static String PROP_USERNAME = "username";
    private final static String PROP_VALIDATIONQUERY = "validationQuery";//验证连接的查询语句
    private final static String PROP_VALIDATIONQUERY_TIMEOUT = "validationQueryTimeout";//验证连接查询语句超时时间
     
    private final static String PROP_INITCONNECTIONSQLS = "initConnectionSqls";//初始化脚本,连接创建成功时执行
    private final static String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed";
    private final static String PROP_REMOVEABANDONED = "removeAbandoned";//是否关闭那些长时间占用但没有进行实际SQL操作的连接
    private final static String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout";//长时间没有实际操作SQL的时间
    private final static String PROP_LOGABANDONED = "logAbandoned";//是否对长时间占用,但没有实际操作SQL的连接,打印Stacktrace
    private final static String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements";
    private final static String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements";
    private final static String PROP_CONNECTIONPROPERTIES = "connectionProperties";


    private final static String[] ALL_PROPERTIES = {
        PROP_DEFAULTAUTOCOMMIT,
        PROP_DEFAULTREADONLY,
        PROP_DEFAULTTRANSACTIONISOLATION,
        PROP_DEFAULTCATALOG,
        PROP_DRIVERCLASSNAME,
        PROP_MAXACTIVE,
        PROP_MAXIDLE,
        PROP_MINIDLE,
        PROP_INITIALSIZE,
        PROP_MAXWAIT,
        PROP_TESTONBORROW,
        PROP_TESTONRETURN,
        PROP_TIMEBETWEENEVICTIONRUNSMILLIS,
        PROP_NUMTESTSPEREVICTIONRUN,
        PROP_MINEVICTABLEIDLETIMEMILLIS,
        PROP_TESTWHILEIDLE,
        PROP_PASSWORD,
        PROP_URL,
        PROP_USERNAME,
        PROP_VALIDATIONQUERY,
        PROP_VALIDATIONQUERY_TIMEOUT,
        PROP_INITCONNECTIONSQLS,
        PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED,
        PROP_REMOVEABANDONED,
        PROP_REMOVEABANDONEDTIMEOUT,
        PROP_LOGABANDONED,
        PROP_POOLPREPAREDSTATEMENTS,
        PROP_MAXOPENPREPAREDSTATEMENTS,
        PROP_CONNECTIONPROPERTIES
    };


   
    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
                                    Hashtable environment)
        throws Exception {


        // We only know how to deal with javax.naming.References
        // that specify a class name of "javax.sql.DataSource"
        if ((obj == null) || !(obj instanceof Reference)) {
            return null;
        }
        Reference ref = (Reference) obj;
        if (!"javax.sql.DataSource".equals(ref.getClassName())) {
            return null;
        }

//读取属性
        Properties properties = new Properties();
        for (int i = 0 ; i < ALL_PROPERTIES.length ; i++) {
            String propertyName = ALL_PROPERTIES[i];
            RefAddr ra = ref.get(propertyName);
            if (ra != null) {
                String propertyValue = ra.getContent().toString();
                properties.setProperty(propertyName, propertyValue);
            }
        }

//创建数据源
        return createDataSource(properties);
    }

 //创建数据源具体方法
    public static DataSource createDataSource(Properties properties) throws Exception {
        BasicDataSource dataSource = new BasicDataSource();
        String value = null;


        value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT);
        if (value != null) {
            dataSource.setDefaultAutoCommit(Boolean.valueOf(value).booleanValue());
        }


        value = properties.getProperty(PROP_DEFAULTREADONLY);
        if (value != null) {
            dataSource.setDefaultReadOnly(Boolean.valueOf(value).booleanValue());
        }


        value = properties.getProperty(PROP_DEFAULTTRANSACTIONISOLATION);
        if (value != null) {
            int level = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
            if ("NONE".equalsIgnoreCase(value)) {
                level = Connection.TRANSACTION_NONE;
            }
            else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
                level = Connection.TRANSACTION_READ_COMMITTED;
            }
            else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) {
                level = Connection.TRANSACTION_READ_UNCOMMITTED;
            }
            else if ("REPEATABLE_READ".equalsIgnoreCase(value)) {
                level = Connection.TRANSACTION_REPEATABLE_READ;
            }
            else if ("SERIALIZABLE".equalsIgnoreCase(value)) {
                level = Connection.TRANSACTION_SERIALIZABLE;
            }
            else {
                try {
                    level = Integer.parseInt(value);
                } catch (NumberFormatException e) {
                    System.err.println("Could not parse defaultTransactionIsolation: " + value);
                    System.err.println("WARNING: defaultTransactionIsolation not set");
                    System.err.println("using default value of database driver");
                    level = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
                }
            }
            dataSource.setDefaultTransactionIsolation(level);
        }


        value = properties.getProperty(PROP_DEFAULTCATALOG);
        if (value != null) {
            dataSource.setDefaultCatalog(value);
        }


        value = properties.getProperty(PROP_DRIVERCLASSNAME);
        if (value != null) {
            dataSource.setDriverClassName(value);
        }


        value = properties.getProperty(PROP_MAXACTIVE);
        if (value != null) {
            dataSource.setMaxActive(Integer.parseInt(value));
        }


        value = properties.getProperty(PROP_MAXIDLE);
        if (value != null) {
            dataSource.setMaxIdle(Integer.parseInt(value));
        }


        value = properties.getProperty(PROP_MINIDLE);
        if (value != null) {
            dataSource.setMinIdle(Integer.parseInt(value));
        }


        value = properties.getProperty(PROP_INITIALSIZE);
        if (value != null) {
            dataSource.setInitialSize(Integer.parseInt(value));
        }


        value = properties.getProperty(PROP_MAXWAIT);
        if (value != null) {
            dataSource.setMaxWait(Long.parseLong(value));
        }


        value = properties.getProperty(PROP_TESTONBORROW);
        if (value != null) {
            dataSource.setTestOnBorrow(Boolean.valueOf(value).booleanValue());
        }


        value = properties.getProperty(PROP_TESTONRETURN);
        if (value != null) {
            dataSource.setTestOnReturn(Boolean.valueOf(value).booleanValue());
        }


        value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS);
        if (value != null) {
            dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(value));
        }


        value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN);
        if (value != null) {
            dataSource.setNumTestsPerEvictionRun(Integer.parseInt(value));
        }


        value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS);
        if (value != null) {
            dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value));
        }


        value = properties.getProperty(PROP_TESTWHILEIDLE);
        if (value != null) {
            dataSource.setTestWhileIdle(Boolean.valueOf(value).booleanValue());
        }


        value = properties.getProperty(PROP_PASSWORD);
        if (value != null) {
            dataSource.setPassword(value);
        }


        value = properties.getProperty(PROP_URL);
        if (value != null) {
            dataSource.setUrl(value);
        }


        value = properties.getProperty(PROP_USERNAME);
        if (value != null) {
            dataSource.setUsername(value);
        }


        value = properties.getProperty(PROP_VALIDATIONQUERY);
        if (value != null) {
            dataSource.setValidationQuery(value);
        }


        value = properties.getProperty(PROP_VALIDATIONQUERY_TIMEOUT);
        if (value != null) {
            dataSource.setValidationQueryTimeout(Integer.parseInt(value));
        }
        
        value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED);
        if (value != null) {
            dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue());
        }


        value = properties.getProperty(PROP_REMOVEABANDONED);
        if (value != null) {
            dataSource.setRemoveAbandoned(Boolean.valueOf(value).booleanValue());
        }


        value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT);
        if (value != null) {     
            dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value));
        }


        value = properties.getProperty(PROP_LOGABANDONED);
        if (value != null) {
            dataSource.setLogAbandoned(Boolean.valueOf(value).booleanValue());
        }


        value = properties.getProperty(PROP_POOLPREPAREDSTATEMENTS);
        if (value != null) {
            dataSource.setPoolPreparedStatements(Boolean.valueOf(value).booleanValue());
        }


        value = properties.getProperty(PROP_MAXOPENPREPAREDSTATEMENTS);
        if (value != null) {
            dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value));
        }


        value = properties.getProperty(PROP_INITCONNECTIONSQLS);
        if (value != null) {
            StringTokenizer tokenizer = new StringTokenizer(value, ";");
            dataSource.setConnectionInitSqls(Collections.list(tokenizer));
        }


        value = properties.getProperty(PROP_CONNECTIONPROPERTIES);
        if (value != null) {
          Properties p = getProperties(value);
          Enumeration e = p.propertyNames();
          while (e.hasMoreElements()) {
            String propertyName = (String) e.nextElement();
            dataSource.addConnectionProperty(propertyName, p.getProperty(propertyName));
          }
        }


        // DBCP-215
        // Trick to make sure that initialSize connections are created
        if (dataSource.getInitialSize() > 0) {
            dataSource.getLogWriter();
        }


        // 返回数据源
        return dataSource;
    }


//获取属性
    static private Properties getProperties(String propText) throws Exception {
      Properties p = new Properties();
      if (propText != null) {
        p.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes()));
      }
      return p;
    }

先分析到这里,明天继续。











你可能感兴趣的:(JAVA框架研究)