一、数据库连接池:
在一般用JDBC 进行连接数据库进行CRUD操作时,每一次都会:
通过:java.sql.Connection conn = DriverManager.getConnection(url,user,password); 重新获取一个数据库的链接再进行操作,这样用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。
所以为了减少服务器的压力,便可用连接池的方法:在启动Web应用时,数据就创建好一定数量的Connection链接
存放到一个容器中,然后当用户请求时,服务器则向容器中获取Connection链接来处理用户的请求,当用户的请求完成后,
又将该Connection 链接放回到该容器中。这样的一个容器称为连接池。
编写一个基本的连接池实现连接复用
步骤:
1、建立一个数据库连接池容器。(因为方便存取,则使用LinkedList集合)
2、初始化一定数量的连接,放入到容器中。
3、等待用户获取连接对象。(该部分要加锁)
|---记得删除容器中对应的对象,放置别人同时获取到同一个对象。
4、提供一个方法,回收用户用完的连接对象。
5、要遵循先入先出的原则。
1 import java.io.InputStream; 2 import java.sql.Connection; 3 import java.sql.DriverManager; 4 import java.sql.SQLException; 5 import java.util.LinkedList; 6 import java.util.Properties; 7 8 9 /** 10 * 一个基本的数据连接池: 11 * 1、初始化时就建立一个容器,来存储一定数量的Connection 对象 12 * 2、用户通过调用MyDataSource 的getConnection 来获取Connection 对象。 13 * 3、再通过release 方法来回收Connection 对象,而不是直接关闭连接。 14 * 4、遵守先进先出的原则。 15 * 16 * 17 * @author 贺佐安 18 * 19 */ 20 public class MyDataSource { 21 private static String url = null; 22 private static String password = null; 23 private static String user = null ; 24 private static String DriverClass = null; 25 private static LinkedList<Connection> pool = new LinkedList<Connection>() ; 26 // 注册数据库驱动 27 static { 28 try { 29 InputStream in = MyDataSource.class.getClassLoader() 30 .getResourceAsStream("db.properties"); 31 Properties prop = new Properties(); 32 prop.load(in); 33 user = prop.getProperty("user"); 34 url = prop.getProperty("url") ; 35 password = prop.getProperty("password") ; 36 DriverClass = prop.getProperty("DriverClass") ; 37 Class.forName(DriverClass) ; 38 39 } catch (Exception e) { 40 throw new RuntimeException(e) ; 41 } 42 } 43 //初始化建立数据连接池 44 public MyDataSource () { 45 for(int i = 0 ; i < 10 ; i ++) { 46 try { 47 Connection conn = DriverManager.getConnection(url, user, password) ; 48 pool.add(conn) ; 49 } catch (SQLException e) { 50 e.printStackTrace(); 51 } 52 } 53 } 54 //、从连接池获取连接 55 public Connection getConnection() throws SQLException { 56 return pool.remove() ; 57 } 58 // 回收连接对象。 59 public void release(Connection conn) { 60 System.out.println(conn+"被回收"); 61 pool.addLast(conn) ; 62 } 63 public int getLength() { 64 return pool.size() ; 65 } 66 }
这样当我们要使用Connection 连接数据库时,则可以直接使用连接池中Connection 的对象。测试如下:
1 import java.sql.Connection; 2 import java.sql.SQLException; 3 4 import org.junit.Test; 5 6 7 public class MyDataSourceTest { 8 9 10 /** 11 * 获取数据库连接池中的所有连接。 12 */ 13 @Test 14 public void Test() { 15 MyDataSource mds = new MyDataSource() ; 16 Connection conn = null ; 17 try { 18 19 for (int i = 0 ; i < 20 ; i ++) { 20 conn = mds.getConnection() ; 21 System.out.println(conn+"被获取;连接池还有:"+mds.getLength()); 22 mds.release(conn) ; 23 } 24 } catch (SQLException e) { 25 e.printStackTrace(); 26 } 27 } 28 }
再运行的时候,可以发现,循环10次后,又再一次获取到了第一次循环的得到的Connection对象。所以,这样可以大大的减轻数据库的压力。上面只是一个简单的数据库连接池,不完美的便是,回收需要调用数据池的release() 方法来进行回收,那么可以不可以直接调用Connection 实例的close 便完成Connection 对象的回收呢?
二、数据源:
> 编写连接池需实现javax.sql.DataSource接口。
> 实现DataSource接口,并实现连接池功能的步骤:
1、在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
2、实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。
利用动态代理和包装设计模式来标准的数据源。
1、包装设计模式实现标准数据源:
这里的用包装设计模式,便是将Connection 接口进行包装。简单总结一下包装设计模式的步骤:
a)定义一个类,实现与被包装类()相同的接口。
|----可以先自己写一个适配器,然后后面继承这个适配器,改写需要改写的方法,提高编程效率。
b)定义一个实例变量,记住被包装类的对象的引用。
c)定义构造方法,转入被包装类的对象。
e)对需要改写的方法,改写。
f)对不需要改写的方法,调用原来被包装类的对应方法。
所以先编写一个类似适配器的类,将Connection 接口的方法都进行实现:
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.Map; import java.util.Properties; /** * 实现Connection 的适配器: * 目的:在使用包装设计模式时方便使用 * @author 贺佐安 * */ public class MyConnectionAdapter implements Connection { //用一个实例变量,记住被包装类的实例引用 protected Connection conn ; //构造函数,转入被包装类的对象 public MyConnectionAdapter(Connection conn) { this.conn = conn ; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return conn.unwrap(iface); } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return conn.isWrapperFor(iface); } @Override public Statement createStatement() throws SQLException { return conn.createStatement(); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { return conn.prepareStatement(sql); } @Override public CallableStatement prepareCall(String sql) throws SQLException { return conn.prepareCall(sql); } @Override public String nativeSQL(String sql) throws SQLException { return conn.nativeSQL(sql); } @Override public void setAutoCommit(boolean autoCommit) throws SQLException { conn.setAutoCommit(autoCommit); } @Override public boolean getAutoCommit() throws SQLException { return conn.getAutoCommit(); } @Override public void commit() throws SQLException { conn.commit() ; } @Override public void rollback() throws SQLException { conn.rollback() ; } @Override public void close() throws SQLException { conn.close() ; } @Override public boolean isClosed() throws SQLException { return conn.isClosed(); } @Override public DatabaseMetaData getMetaData() throws SQLException { return conn.getMetaData(); } @Override public void setReadOnly(boolean readOnly) throws SQLException { conn.setReadOnly(readOnly); } @Override public boolean isReadOnly() throws SQLException { return conn.isReadOnly(); } @Override public void setCatalog(String catalog) throws SQLException { conn.setCatalog(catalog) ; } @Override public String getCatalog() throws SQLException { return conn.getCatalog(); } @Override public void setTransactionIsolation(int level) throws SQLException { conn.setTransactionIsolation(level) ; } @Override public int getTransactionIsolation() throws SQLException { return conn.getTransactionIsolation(); } @Override public SQLWarning getWarnings() throws SQLException { return conn.getWarnings(); } @Override public void clearWarnings() throws SQLException { conn.clearWarnings() ; } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { return conn.createStatement(resultSetType, resultSetConcurrency); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return conn.prepareStatement(sql, resultSetType, resultSetConcurrency); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return conn.prepareCall(sql, resultSetType, resultSetConcurrency); } @Override public Map<String, Class<?>> getTypeMap() throws SQLException { return conn.getTypeMap(); } @Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException { conn.setTypeMap(map) ; } @Override public void setHoldability(int holdability) throws SQLException { conn.setHoldability(holdability) ; } @Override public int getHoldability() throws SQLException { return conn.getHoldability(); } @Override public Savepoint setSavepoint() throws SQLException { return conn.setSavepoint(); } @Override public Savepoint setSavepoint(String name) throws SQLException { return conn.setSavepoint(name); } @Override public void rollback(Savepoint savepoint) throws SQLException { conn.rollback(savepoint); } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { conn.releaseSavepoint(savepoint); } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { return conn.prepareStatement(sql, autoGeneratedKeys); } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { return conn.prepareStatement(sql, columnIndexes); } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { return conn.prepareStatement(sql, columnNames); } @Override public Clob createClob() throws SQLException { return conn.createClob(); } @Override public Blob createBlob() throws SQLException { return conn.createBlob(); } @Override public NClob createNClob() throws SQLException { return conn.createNClob(); } @Override public SQLXML createSQLXML() throws SQLException { return conn.createSQLXML(); } @Override public boolean isValid(int timeout) throws SQLException { return conn.isValid(timeout); } @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { conn.setClientInfo(name, value) ; } @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { conn.setClientInfo(properties) ; } @Override public String getClientInfo(String name) throws SQLException { return conn.getClientInfo(name); } @Override public Properties getClientInfo() throws SQLException { return conn.getClientInfo(); } @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { return conn.createArrayOf(typeName, elements); } @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { return conn.createStruct(typeName, attributes); } }