您的位置:首页 > 其它

【JDBC单例】和【C3P0连接池基本用法】的对比

2012-04-19 19:18 281 查看
最近需要从一张表中查询大量数据,做了如下实验:

平台:

MySQL5.1.52(最大连接数设为1000)

CentOS 6.2

HP台式机(酷睿i5-2400 / 8G内存/ 500GB Sata3 硬盘)

在本机通过JDBC连接数据库

将基本的单例模式和基本的C3P0连接池的使用做了如下对比。

1、单例

代码如下:

package t2.dbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import t2.util.Configuration;

public class SingletonConn
{
private Connection connection = null;
private Statement statement = null;
private ResultSet resultSet = null;
private static String DBClassName = null;
private static String DBUrl = null;
private static String DBUser = null;
private static String DBPassword  = null;

private static SingletonConn instance = null;

protected SingletonConn()
{
}

static
{
try
{
Configuration configuration = new Configuration("db.conf");
DBClassName = configuration.getItemValue("ClassName");
DBUrl = configuration.getItemValue("URL");
DBUser = configuration.getItemValue("User");
DBPassword = configuration.getItemValue("Pass");

Class.forName(DBClassName);
}
catch (Exception e)
{
e.printStackTrace();
}
}

public static synchronized SingletonConn getInstance()
{
if(instance == null)
{
instance = new SingletonConn();
}
return instance;
}

private synchronized void getConnection() throws SQLException
{
//仅当connection失效时才重新获取
if (connection == null || connection.isValid(10) == false)
{
connection = DriverManager.getConnection(DBUrl, DBUser, DBPassword);
}
}

private synchronized void getStatement() throws SQLException
{
getConnection();
//仅当statement失效时才重新创建
if (statement == null || statement.isClosed() == true)
{
statement = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
}
}

public synchronized void close() throws SQLException
{
if (resultSet != null)
{
resultSet.close();
resultSet = null;
}
if (statement != null)
{
statement.close();
statement = null;
}
if (connection != null)
{
connection.close();
connection = null;
}
}

public synchronized ResultSet executeQuery(String sql) throws SQLException
{
getStatement();
if (resultSet != null && resultSet.isClosed() == false)
{
resultSet.close();
}
resultSet = null;
resultSet = statement.executeQuery(sql);
return resultSet;
}

public synchronized int executeUpdate(String sql) throws SQLException
{
int result = 0;
getStatement();
result = statement.executeUpdate(sql);
return result;
}

}
2、基本的C3P0代码:

package t2.dbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;

import t2.util.Configuration;

public class PooledConn
{
private static String DBClassName = null;
private static String DBUrl = null;
private static String DBUser = null;
private static String DBPassword  = null;

private static ComboPooledDataSource cpds = null;;

private static PooledConn instance = null;

protected PooledConn() { }

static
{
try
{
Configuration configuration =
new Configuration("db.conf");
DBClassName = configuration.getItemValue("ClassName");
DBUrl = configuration.getItemValue("URL");
DBUser = configuration.getItemValue("User");
DBPassword = configuration.getItemValue("Pass");

cpds = new ComboPooledDataSource();
cpds.setDriverClass(DBClassName);
cpds.setJdbcUrl(DBUrl);
cpds.setUser(DBUser);
cpds.setPassword(DBPassword);

cpds.setInitialPoolSize(20);
cpds.setMinPoolSize(10);
cpds.setAcquireIncrement(5);
cpds.setMaxPoolSize(50);
}
catch (Exception e)
{
e.printStackTrace();
}
}

public static synchronized PooledConn getInstance()
{
if(instance == null)
{
instance = new PooledConn();
}
return instance;
}

public synchronized void close()
{
try
{
DataSources.destroy(cpds);
}
catch (SQLException e)
{
e.printStackTrace();
}
}

public synchronized ResultSet executeQuery(String sql)
{
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try
{
conn = cpds.getConnection();
st = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
rs = st.executeQuery(sql);
}
catch (SQLException e)
{
e.printStackTrace();
}
return rs;
}

public synchronized int executeUpdate(String sql)
{
int result = 0;
Connection conn = null;
Statement st = null;
try
{
conn = cpds.getConnection();
st = conn.createStatement();
result = st.executeUpdate(sql);
st.close();
conn.close();
}
catch (Exception e)
{
e.printStackTrace();
}
return result;
}

}


3、测试程序:

package t2.dbc;

public class Conn extends SingletonConn
{
private Conn() {}
}


package t2.test;

import java.sql.ResultSet;
import java.sql.SQLException;

import t2.dbc.Conn;

public class BDAccessTest
{
public static void main (String[] args) throws SQLException
{
int i = 100000;
long timer = System.currentTimeMillis();
while (i-- > 0)
{
ResultSet rs =  Conn.getInstance().executeQuery("select * from t_query where f_id=" + i);
while (rs.next());
}
timer = System.currentTimeMillis() - timer;
System.out.println("处理时间:" + timer);
}
}


4、结果

t_query表中有一个f_id字段、建立了主键和哈希索引,还有一个f_token字段为平均长度50的varchar。引擎类型为innodb

单例只会占用1个数据库连接,可以达到每秒7000-8000条的查询速度,并且不会有异常。

C3P0平均会占用最大连接数*80%的连接数,当查询速度达到每秒100条时,持续一分钟左右就会出现JDBC异常。

但是单例没有保持连接的能力,一旦超过一定时间没有使用(大约几百毫秒),连接就会被自动释放掉,每次新建连接都需要140毫秒左右的时间

而C3P0连接池会池化连接,随时取用,平均每次取用只需要10-20毫秒。

所以:

如果只有少量的进程并发(单例在每个进程中都会有唯一的实例),并且需要连续执行查询(一般的应用可能不会有这种情况,但是在做数据处理、分析的时候可能会有),单例就很好,一旦建立连接速度很快。

如果是很多客户端并发,并且随机地访问数据库(比如一般的动态网站),那么用数据库连接池更好一些。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: