问题思考:
如果一直在获取jdbc连接,假设一直操作数据库,是否浪费内存
缺点:用户每次请求都需要向数据库获得链接,
而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。
假设网站一天10万访问量,数据库服务器就需要创建10万次连接,
极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。
连接池概念
1)连接池是一个进程
多个连接是在一个进程里面存储、管理的。这个进程保存所有的连接,
当我们打开连接,如果有未用连接可用,则返回该连接。如果池中的连接都用完了,
则创建一个新的连接保存到连接池。而但我们关闭连接的时候,
连接池里面并不关闭连接,而是返回连接池中并标记为可重用的状态,
等待重新连接直到等待超时。再次打开连接的时候,
我们就可以重用上次的连接。如果在这个时间内没有连接请求(打开连接),这个数据 库连接将被关闭,并从连接池中移除这个连接实例。如果池中连接到达了最大连接数, 请求进入等待队列直到空闲连接可用。如果在可获取连接对象之前超时期限已过(由 Connect Timeout 连接字符串属性来决定),则将出错。
2)该进程保存连接并使其处于活动状态,使连接可以被重复使用
应用程序访问底层的数据源的时候是通过OS的数据访问组件或者说Sql Client数据访问
提供程序进行访问的。都是通过系统提供的组件去访问数据库服务器的数据库的。连接
是通过这些组件建立的,连接池是在这些组件之上的,它存在于应用程序的进程里面。 因此需要重用连接,就是在这一个进程里面重用。例如:两个WinForm程序在不同的计
算机上,他们同时连接一个数据库服务器,这个时候,连接池就没办法起作用,因为连
接池是一个进程里面。这时候,我们可以在数据库服务器上层搭建一个Web Service,
而Web Service 和数据库服务器之间使用的是连接池,数据库服务器的压力就会小。
自定义连接池
模拟连接池基本效果,自己定义连接池,思想就是设置一个集合,往集合中初始化添加几个连接,当使用连接的时候,从连接池中获取,当不使用时,将连接归还到连接池中
public class MyDataSource {
public static ArrayList<Connection> connectionPoor = new ArrayList<Connection>();
private static int size = 10;
static {
for (int i = 0; i < size; i++) {
connectionPoor.add(JDBCUtils.connect());
}
}
public static Connection getConnection() {
Connection connection = null;
if (connectionPoor.size() > 0) {
connection = connectionPoor.get(0);
connectionPoor.remove(0);
}
return connection;
}
public static void close(Connection connection) {
connectionPoor.add(connection);
}
}
第三方连接池
DBCP 是 Apache 软件基金组织下的开源连接池实现,使用DBCP数据源,应用程序应在系统中增加如下两个 jar 文件:
Commons-dbcp.jar:连接池的实现
Commons-pool.jar:连接池实现的依赖库
Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。
DBCP连接池使用
第一步 配置properties文件
#\u8FDE\u63A5\u8BBE\u7F6E driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mydb1 username=root password=123456 #<!-- \u521D\u59CB\u5316\u8FDE\u63A5 --> initialSize=10 #\u6700\u5927\u8FDE\u63A5\u6570\u91CF maxActive=50 #<!-- \u6700\u5927\u7A7A\u95F2\u8FDE\u63A5 --> maxIdle=20 #<!-- \u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5 --> minIdle=5 #<!-- \u8D85\u65F6\u7B49\u5F85\u65F6\u95F4\u4EE5\u6BEB\u79D2\u4E3A\u5355\u4F4D 6000\u6BEB\u79D2/1000\u7B49\u4E8E60\u79D2 --> maxWait=60000 #JDBC\u9A71\u52A8\u5EFA\u7ACB\u8FDE\u63A5\u65F6\u9644\u5E26\u7684\u8FDE\u63A5\u5C5E\u6027\u5C5E\u6027\u7684\u683C\u5F0F\u5FC5\u987B\u4E3A\u8FD9\u6837\uFF1A[\u5C5E\u6027\u540D=property;] #\u6CE8\u610F\uFF1A"user" \u4E0E "password" \u4E24\u4E2A\u5C5E\u6027\u4F1A\u88AB\u660E\u786E\u5730\u4F20\u9012\uFF0C\u56E0\u6B64\u8FD9\u91CC\u4E0D\u9700\u8981\u5305\u542B\u4ED6\u4EEC\u3002 connectionProperties=useUnicode=true;characterEncoding=gbk #\u6307\u5B9A\u7531\u8FDE\u63A5\u6C60\u6240\u521B\u5EFA\u7684\u8FDE\u63A5\u7684\u81EA\u52A8\u63D0\u4EA4\uFF08auto-commit\uFF09\u72B6\u6001\u3002 defaultAutoCommit=true #driver default \u6307\u5B9A\u7531\u8FDE\u63A5\u6C60\u6240\u521B\u5EFA\u7684\u8FDE\u63A5\u7684\u53EA\u8BFB\uFF08read-only\uFF09\u72B6\u6001\u3002 #\u5982\u679C\u6CA1\u6709\u8BBE\u7F6E\u8BE5\u503C\uFF0C\u5219\u201CsetReadOnly\u201D\u65B9\u6CD5\u5C06\u4E0D\u88AB\u8C03\u7528\u3002\uFF08\u67D0\u4E9B\u9A71\u52A8\u5E76\u4E0D\u652F\u6301\u53EA\u8BFB\u6A21\u5F0F\uFF0C\u5982\uFF1AInformix\uFF09 defaultReadOnly= #driver default \u6307\u5B9A\u7531\u8FDE\u63A5\u6C60\u6240\u521B\u5EFA\u7684\u8FDE\u63A5\u7684\u4E8B\u52A1\u7EA7\u522B\uFF08TransactionIsolation\uFF09\u3002 #\u53EF\u7528\u503C\u4E3A\u4E0B\u5217\u4E4B\u4E00\uFF1A\uFF08\u8BE6\u60C5\u53EF\u89C1javadoc\u3002\uFF09NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED
第二步:书写工具类DBCPUtils
public class DBCPUtils { private static DataSource ds; static { try { //加载配置文件 InputStream is = DBCPUtils.class.getClassLoader() .getResourceAsStream("dbcpcfg.properties"); Properties p = new Properties(); p.load(is); //获取连接池 ds = BasicDataSourceFactory.createDataSource(p); } catch (Exception e) { e.printStackTrace(); } } /** * 获取连接 * * @return */ public static synchronized Connection getConneciton() { try { return ds.getConnection(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 关闭连接 * @param rs * @param st * @param con */ public static void release(ResultSet rs, Statement st, Connection con) { try { if (rs != null) { rs.close(); rs = null; } } catch (SQLException e) { e.printStackTrace(); } try { if (st != null) { st.close(); st = null; } } catch (SQLException e) { e.printStackTrace(); } try { if (con != null) { con.close(); } } catch (SQLException e) { e.printStackTrace(); } }
}
C3P0连接池
第一步 src下配置c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb1</property> <property name="user">root</property> <property name="password">123456</property> <property name="acquireIncrement">5</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">5</property> <property name="maxPoolSize">20</property> </default-config>
第二步 配置工具类
public class C3P0Util { private static DataSource ds = new ComboPooledDataSource(); public static synchronized Connection getConneciton() { try { return ds.getConnection(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } public static void release(ResultSet rs, Statement st, Connection con) { try { if (rs != null) { rs.close(); rs = null; } } catch (SQLException e) { e.printStackTrace(); } try { if (st != null) { st.close(); st = null; } } catch (SQLException e) { e.printStackTrace(); } try { if (con != null) { con.close(); } } catch (SQLException e) { e.printStackTrace(); } }
}