1.数据库连接池
应用程序在与数据库交互过程中,与数据库建立连接的过程开销较大,如果每次使用都要重新创建新的连接,会无畏浪费数据库资源,增加数据库压力,影响程序性能。通常选择在初始化时,建立一定数量的数据库连接,并放入连接池中,这样用户可以重复使用连接池的已经存在的数据库连接,减小创建数据库连接的开销,提高程序访问性能。
1)初始化连接数:连接池初始时建立的数据库连接数量。
2)最大连接数:连接池能建立的最大连接数量,如果请求超过次数,后面的连接请求将会放入等待队列中。
在初始化连接都被使用时,超过初始化数量的连接请求的建立的开销等价于新建一个数据库连接的开销,但在使用之后不会被释放,而是被添加到数据库连接池中重复使用。
2.建立数据库连接池
1)建立数据库连接池connectionPool, 根据初始化连接数initCount建立Connection 对象,放入到连接池
2) 连接请求时,查询是否 池中是否有连接,如果没有,并在不超过最大连接的情况下,建立新的连接,否则,提示超出最大连接异常
3)连接请求结束时,释放连接到连接池中,释放连接并不是真的关闭连接,只是把连接放到连接池中,等待重复使用
public class MyDataSource implements DataSource{
public LinkedList<Connection> connectionsPool = new LinkedList<Connection>();
//初始连接数
private static int initCount = 5;
//最大连接数
private static int maxCount = 10;
//当前连接
static int currentCount = 0;
public MyDataSource()
{
for(int i = 0; i< initCount ;i++)
{
try {
this.connectionsPool.addLast(this.createConnection());
currentCount ++;
} catch (SQLException e) {
throw new ExceptionInInitializerError(e);
}
}
}
public Connection getConnection() throws SQLException
{
//保证多个线程同时来拿的时候不会拿到同一个connection
synchronized (connectionsPool) {
if(this.connectionsPool.size() > 0)
{
return this.connectionsPool.removeFirst();
}
if(this.currentCount < maxCount)
{
currentCount++;
return this.createConnection();
}
throw new SQLException("已没有连接可用");
}
}
public void free(Connection conn)
{
this.connectionsPool.addLast(conn);
}
private Connection createConnection() throws SQLException
{
Connection realConn = DriverManager.getConnection(Constant.url,Constant.username,Constant.password);
//使用proxy动态代理
MyConnectionHandler proxy =new MyConnectionHandler(this);
return proxy.bind(realConn);
}
}
以上就是一个简单的数据库连接池, 连接池由一个List对象维护,首先初始化5个Connection对象,并设置最大连接数量为10,当请求到来时,查询返回并删除List的首个对象,并在结束连接时,重新将Connection对象放到List尾部,从而实现连接的重复使用。
class MyConnectionHandler implements InvocationHandler {
private Connection realConnection;
private Connection warpedConnection ;
private MyDataSource2 dataSource;
//最大使用次数
private int maxUseCount = 10;
//当前使用次数
private int currentUseCount =0;
MyConnectionHandler(MyDataSource2 dataSource)
{
this.dataSource = dataSource;
}
/**
* 使用proxy
* @param realConn
* @return
*/
Connection bind(Connection realConn)
{
this.realConnection = realConn;
this.warpedConnection = (Connection)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{Connection.class}, this);
return warpedConnection;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//如果是close方法
if("close".equals(method.getName()))
{
this.currentUseCount++;
if(this.currentUseCount < this.maxUseCount)
{
this.dataSource.connectionsPool.addLast(this.warpedConnection);
}
else
{
this.realConnection.close();
//当前连接数减1
this.dataSource.currentCount--;
}
}
return method.invoke(this.realConnection,args);
}
}
在本来中,还使用了Proxy代理技术,主要是为了不改被用户的使用习惯,对close方法进行了处理,即使用户使用了close方法而不是使用free方法去关闭连接,仍然可以将连接加入的数据池中,而不是真的关闭连接.
/**
* 注册jdbc驱动
* @author Administrator
*
*/
public class JdbcUtils {
private static DataSource myDataSource = null;
private JdbcUtils(){}
/**
*注册jdbc驱动,初始化连接池
*/
static
{
try {
Class.forName("com.mysql.jdbc.Driver");
myDataSource = (DataSource) new MyDataSource();
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
/**
* 获取连接
* @return
* @throws SQLException
*/
public static Connection ConnecteMysql() throws SQLException {
return myDataSource.getConnection();
}
/**
* 关闭数据库连接
* @param conn
* @param st
* @param rs
* @throws SQLException
*/
public static void closeConnection(Connection conn, Statement st, ResultSet rs)
{
try
{
if(rs != null)
{
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
finally
{
try
{
if (st != null)
{
st.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
finally
{
if(conn != null)
{
try {
conn.close();
//myDataSource.free(conn);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}