数据库连接池是在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.Reference
s
// 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;
}
先分析到这里,明天继续。