前面一篇介绍了数据库连接池,也就是说以后,我们一个业务处理完了,不应该直接调用mysql实现的close方法,而是要把这个连接对象放回到连接池中取,供下一个请求使用。本篇就来看看如何解决这个close方法的问题。前面一篇代码中模拟了连接池pool的实现,就是因为每个人都可以写自己的连接池实现,造成了不规范,为了规范这种行为,sun公司提供了一个接口javax.sql.DataSource,这样大家都去实现这个接口,别人看到你实现了这个接口的代码就明白了这是一个连接池的实现。
1.MyDataSource.java
写一个类实现接口javax.sql.DataSource
package com.anthony.pool;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.logging.Logger;
import javax.sql.DataSource;
import com.anthony.utils.DBUtils;
public class MyDataSource implements DataSource {
//创建一个存放连接的池子,大小为10
private static LinkedList<Connection> pool = (LinkedList<Connection>) Collections.synchronizedCollection(new LinkedList());
static {
try {
for (int i = 0; i < 10; i++) {
Connection conn = DBUtils.getConnection();
pool.add(conn);
}
} catch (Exception e) {
throw new ExceptionInInitializerError("初始化数据库连接失败,请检查配置文件。");
}
}
public Connection getConnection() throws SQLException {
Connection conn = null;
if(pool.size() > 0) {
conn = pool.removeFirst();
//对conn进行包装
MyConnection myConn = new MyConnection(conn, pool); //得到一个包装后的MyConnection对象
return myConn;
}else {
// 1 等待
// 2.等待超时,新创建一个连接
throw new RuntimeException("服务器忙");
}
}
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}
我们重点实现getConnection()方法,其他方法默认就好。
2.MyConnection.java
MyConnection类包装mysql中实现的Connection。
package com.anthony.pool;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
/*1)编写一个类,实现与被包装类相同的接口(具备相同的行为)
2)定义一个被包装类类型的变量
3)定义构造方法,把被包装类的对象注入,给包装类变量赋值。
4)对于不需要改写的方法,调用原有的方法。
5)对于需要改写的方法,写自己的代码。*/
public class MyConnection implements Connection {
private Connection oldConnection;// com.mysql.jdbc.Connection
private LinkedList<Connection> pool;
public MyConnection(Connection oldConnection, LinkedList<Connection> pool) {
this.oldConnection = oldConnection; //得到com.mysql.jdbc.Connection
this.pool = pool; //得到连接池对象
}
@Override
public void close() throws SQLException {
pool.addLast(oldConnection); //把用完connection添加回集合中
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return oldConnection.prepareStatement(sql);
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
throws SQLException {
return oldConnection.prepareStatement(sql,resultSetConcurrency);
}
//以下省略多个实现方法
}
重点看构造方法和close方法。构造方法就是对conn对象进行包装,close方法就是把用户结束的连接对象进行放回到集合里。
3.TestJDBC.java
写一个测试类。
package com.anthony.pool;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.junit.Test;
public class TestJDBC {
@Test
public void test() {
DataSource ds = new MyDataSource();
Connection conn = null;
PreparedStatement ps = null;
try {
conn = ds.getConnection(); //从池中取出一个连接
ps = conn.prepareStatement("select * from users");
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}