数据库连接池中为什么需要用装饰者模式?
自定义连接池中存在严重的问题,用户调用getConnection()获得连接后,必须使用release()方法进行连接的归还,如果用户调用conn.close()将连接真正的释放,连接池中出现无连接可用。
因此我们在这里使用装饰者模式对close方法进行增强,即使调用了close()方法,并不对关闭连接而是对连接进行归还,将连接归还到连接池中。
解决问题
首先我们先编写一个JDBCUtils用来连接数据库
public class JDBCUtils {
public static String drive;
public static String url;
public static String username;
public static String password;
static {
try {
//读取数据库的配置文件
InputStream inputStream = new FileInputStream(new File("db.properties"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
Connection con = null;
try {
Class.forName(drive);
//创建连接
con = DriverManager.getConnection(url,username,password);
} catch (Exception e) {
e.printStackTrace();
}
return con;
}
}
接下来编写一个数据库连接池,这里用集合来代替连接池
public class MyDataSource implements DataSource {
private static List connectionList = new ArrayList<>();
static {
//创建时放入5个连接
for(int i = 0;i<5;i++){
//得到数据库连接
Connection connection = JDBCUtils.getConnection();
//对连接进行增强
MyConnection myConnection = new MyConnection(connectionList,connection);
//将增强后的连接放入池中
connectionList.add(myConnection);
}
}
@Override
public Connection getConnection() throws SQLException {
if(connectionList.size() == 0){
//若连接池中没有连接,就创建5个连接放入
for(int i = 0;i<5;i++){
//得到数据库连接
Connection connection = JDBCUtils.getConnection();
//对连接进行增强
MyConnection myConnection = new MyConnection(connectionList,connection);
//将增强后的连接放入池中
connectionList.add(myConnection);
}
}
//从池中取出一个连接
Connection con = connectionList.remove(0);
return con;
}
public void backConnection(Connection con){
connectionList.add(con);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public T unwrap(Class iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class> iface) throws SQLException {
return false;
}
@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;
}
}
其实代码很简单,大家结合注释看一看很快就明白了是什么意思了,现在我们来看一下如何利用装饰者模式如何对连接进行增强
public class MyConnection implements Connection {
private List connectionList;
private Connection con;
public MyConnection(List connections,Connection con){
this.connectionList = connections;
this.con = con;
}
@Override
public void close() throws SQLException {
connectionList.add(con);
}
@Override
public Statement createStatement() throws SQLException {
return null;
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return null;
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
return null;
}
@Override
public String nativeSQL(String sql) throws SQLException {
return null;
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
}
@Override
public boolean getAutoCommit() throws SQLException {
return false;
}
@Override
public void commit() throws SQLException {
}
@Override
public void rollback() throws SQLException {
}
@Override
public boolean isClosed() throws SQLException {
return false;
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
return null;
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
}
@Override
public boolean isReadOnly() throws SQLException {
return false;
}
@Override
public void setCatalog(String catalog) throws SQLException {
}
@Override
public String getCatalog() throws SQLException {
return null;
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
}
@Override
public int getTransactionIsolation() throws SQLException {
return 0;
}
@Override
public SQLWarning getWarnings() throws SQLException {
return null;
}
@Override
public void clearWarnings() throws SQLException {
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return null;
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return null;
}
@Override
public Map> getTypeMap() throws SQLException {
return null;
}
@Override
public void setTypeMap(Map> map) throws SQLException {
}
@Override
public void setHoldability(int holdability) throws SQLException {
}
@Override
public int getHoldability() throws SQLException {
return 0;
}
@Override
public Savepoint setSavepoint() throws SQLException {
return null;
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
return null;
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return null;
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return null;
}
@Override
public Clob createClob() throws SQLException {
return null;
}
@Override
public Blob createBlob() throws SQLException {
return null;
}
@Override
public NClob createNClob() throws SQLException {
return null;
}
@Override
public SQLXML createSQLXML() throws SQLException {
return null;
}
@Override
public boolean isValid(int timeout) throws SQLException {
return false;
}
@Override
public void setClientInfo(String name, String value) throws SQLClientInfoException {
}
@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
}
@Override
public String getClientInfo(String name) throws SQLException {
return null;
}
@Override
public Properties getClientInfo() throws SQLException {
return null;
}
@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
return null;
}
@Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
return null;
}
@Override
public void setSchema(String schema) throws SQLException {
}
@Override
public String getSchema() throws SQLException {
return null;
}
@Override
public void abort(Executor executor) throws SQLException {
}
@Override
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
}
@Override
public int getNetworkTimeout() throws SQLException {
return 0;
}
@Override
public T unwrap(Class iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class> iface) throws SQLException {
return false;
}
}
首先他要实现Connection这个接口,这个接口就类似于我们在装饰者文章中的drink接口,有两个属性,类型分别是List和Connection,含有一个构造方法接受传入的两个类型的参数对本类的两个属性进行赋值,分别代表,连接池和我们当前获得的连接,然后重写了close方法,在调用这个方法的时候,我们使用的是connectionList.add(con) 将我们创建的时候或得到的连接再次加入到连接池中去,到了这里我们发现问题已经解决了。
下面我们来测试一下
我们发现大功告成。
总结
1、编写JDBCUtils来连接数据库
2、编写MyDataSource 连接池类实现DataSource接口,用list来代替连接池
3、使用装饰者模式编写MyConnection 实现对close方法进行强化,将连接归还到连接池中去,而不是关闭连接。
当某个对象的职能不满足于我们所使用的时,我们可以考虑一下是否可以通过装饰者模式对其方法进行强化,比如我们在装饰者讲解文章中提到的当我们需要加冰可乐的时候,但是我们只有普通的可乐,我们就可以通过装饰者模式对这个可乐进行强化,从而得到加冰的可乐。详情可见:http://www.lindasoft.com/view/article/details?articleId=607