DBCP与C3P0连接池以及基本分页的实现
为什么使用连接池?
1.连接资源宝贵,需要对连接管理
2.操作数据库,频繁的创建连接与关闭连接消耗资源
3.使用连接池可预先创建一组连接,使用时取出一个,用完放回池中
1.自定义连接池
为了理解连接池,在使用连接池前可自定义一个连接池
* 模拟数据库连接池
* init_count连接池中的连接数
* max_count数据库的最大连接数
* current_count当前的连接数
*
*如果想调用con.close()得到像pool.realeaseConnection(con)的效果
* 方法一:实现Connection接口,重写close方法
* 方法二:动态代理proxy
* 这里仅演示动态代理
* */
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
public class MyPool {
private int init_count = 3; //初始化连接数
private int current_count=0; //当前连接数
private int max_count = 6; //最大连接数
private LinkedList<Connection> list = new LinkedList<>();
//初始化连接数,默认为3个
public MyPool(){
for(int i=0;i<init_count;i++){
//记录当前连接数
current_count++;
//创建连接并放入连接池中
Connection con = createConnection();
list.addLast(con);
}
}
//获取连接
public Connection getConnection(){
//当连接池中存有连接时
if(list.size()>0){
Connection con = list.removeFirst();
return con;
//连接池中连接已用完,且当前连接数小于最大连接数
}else if(current_count<max_count){
current_count++;
Connection con = createConnection();
return con;
}
throw new RuntimeException("已达到最大连接数");
}
//创建连接
public Connection createConnection(){
Connection proxy = null;
try {
Class.forName("com.mysql.jdbc.Driver");
final Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mytest","root","student");
//动态代理
proxy = (Connection)Proxy.newProxyInstance(
con.getClass().getClassLoader(), //类加载器
new Class[]{Connection.class}, //目标对象实现的接口,若目标对象是具体类的对象,使用如下:con.getClass.getInterfaces();
new InvocationHandler() { //当调用con的方法时,自动触发事务处理器
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null; //返回的结果
String methodName = method.getName(); //触发事务处理器的方法名
if("close".equals(methodName)){
realeaseConnection(con);
}else{
result = method.invoke(con, args);
}
return result;
}
}
);
} catch (Exception e) {
e.printStackTrace();
}
return proxy;
}
//释放连接
public void realeaseConnection(Connection con){
//连接池连接数小于初始化连接数,则放回池中
if(list.size()<init_count){
list.addLast(con);
}else{
try {
//关闭
current_count--;
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws SQLException{
MyPool pool = new MyPool();
pool.getConnection();
pool.getConnection();
pool.getConnection();
pool.getConnection();
Connection con1 = pool.getConnection();
Connection con =pool.getConnection();
System.out.println(pool.current_count);
System.out.println(pool.max_count);
System.out.println(pool.init_count);
/* pool.realeaseConnection(con);
pool.realeaseConnection(con1);*/
con.close();
con1.close();
pool.getConnection();
pool.getConnection();
}
}
代理:
如果对某个接口中的某个指定的方法的功能进行扩展,而不想实现接口里所有方法,可以使用(动态)代理模式!
Java中代理模式:静态/动态/Cglib代理(spring)
使用动态代理,可以监测接口中方法的执行!
2.开源的连接池技术
2.1 DBCP
DBCP 是 Apache 软件基金组织下的开源连接池实现,使用DBCP数据源,应用程序应在系统中增加如下两个 jar 文件:
•Commons-dbcp.jar:连接池的实现
Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。
核心类:BasicDataSource
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
/*
* DBCP数据源
*
* */
public class DBCPUtil {
//通过硬编码方式创建
public Connection getConnection() throws SQLException{
BasicDataSource ds = new BasicDataSource();
ds.setUrl("jdbc:mysql://localhost:8080/mytest"); //数据库url
ds.setDriverClassName("com.mysql.jdbc.Driver"); //驱动
ds.setUsername("root"); //用户名
ds.setPassword("student"); //密码
ds.setMaxActive(30); //最大连接数
ds.setInitialSize(10); //初始化连接数
ds.setMaxIdle(6000); //最大空闲时间
ds.setMaxWait(1000); //最大等待时间
return ds.getConnection();
}
//通过配置文件创建[**推荐**],便于维护
public Connection getCon() throws Exception{
Properties prop = new Properties();
//加载配置文件
prop.load(this.getClass().getResourceAsStream("db.properties"));
//读取配置文件创建数据源
BasicDataSource ds = (BasicDataSource) BasicDataSourceFactory.createDataSource(prop);
return ds.getConnection();
}
}
/*src下的配置文件示例*/
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mytest?userUnicode=true&characterEncoding=utf8
username=root
password=student
maxActive=100
initialSize=30
maxIdle=10
maxWait=1000 //连接最大等待时间
removeAbandoned=true
removeAbandonedTimeout=18000 //超出空闲时间自动释放连接
2.2 C3P0
C3P0连接池:最常用的连接池技术!Spring框架,默认支持C3P0连接池技术!
jar包:c3p0-0.9.1.2.jar
核心类:CombopooledDataSource ;
import java.sql.Connection;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Util {
//硬编码方式,使用C3P0连接池管理连接
public Connection getConnection() throws Exception{
ComboPooledDataSource dpds = new ComboPooledDataSource();
// 设置连接参数:url、驱动、用户密码、最大连接数、初始连接数、最大空闲时间
dpds.setJdbcUrl("jdbc:mysql://localhost:8080/mytest");
dpds.setDriverClass("com.mysql.jdbc.Driver");
dpds.setUser("root");;
dpds.setPassword("student");
dpds.setMaxPoolSize(30);
dpds.setInitialPoolSize(10);
dpds.setMaxIdleTime(3000);
return dpds.getConnection();
}
//XML配置方式,使用C3P0连接池管理连接
public Connection getConn() throws SQLException{
// 创建c3p0连接池核心工具类
// 自动加载src下c3p0的配置文件【c3p0-config.xml】,c3p0-config.xml文件可在源代码中copy过来修改
ComboPooledDataSource dpds = new ComboPooledDataSource();//添加参数configName可指定配置,否则使用默认配置
return dpds.getConnection();
}
}
/*src下配置文件示例*/
<c3p0-config>
<default-config>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc_demo
</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">3</property>
<property name="maxPoolSize">6</property>
<property name="maxIdleTime">1000</property>
</default-config>
<!-- 可以选择配置oracle数据库,实现多个数据库的使用 -->
<named-config name="dumbTestConfig">
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc_demo
</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">3</property>
<property name="maxPoolSize">6</property>
<property name="maxIdleTime">1000</property>
</named-config>
</c3p0-config>
3. 分页技术
JSP页面,用来显示数据! 如果数据有1000条,分页显示,每页显示10条,共100页; 好处: 利于页面布局,且显示的效率高!
这里仅做Javabean和dao层的处理。
public class PageBean<T> {
private int currentPage=1; //当前页
private int pageCount=6; //每页条数
private int totalCount; //总条数
private int totalPage; //总页数
private List<T> pageData; //查询到的数据
public PageBean(int currentPage, int pageCount, int totalCount, int totalPage, List<T> pageData) {
super();
this.currentPage = currentPage;
this.pageCount = pageCount;
this.totalCount = totalCount;
this.totalPage = totalPage;
this.pageData = pageData;
}
public PageBean() {
super();
}
@Override
public String toString() {
return "PageBean [currentPage=" + currentPage + ", pageCount=" + pageCount + ", totalCount=" + totalCount
+ ", totalPage=" + totalPage + ", pageData=" + pageData + "]";
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getPageCount() {
return pageCount;
}
public void setPageCount(int pageCount) {
this.pageCount = pageCount;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getTotalPage() {
return totalCount%pageCount==0?totalCount/pageCount:totalCount/pageCount+1;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public List<T> getPageData() {
return pageData;
}
public void setPageData(List<T> pageData) {
this.pageData = pageData;
}
}
public class EmployeeDAOImpl {
public void getAll(PageBean<Employee> pageBean) throws Exception{
//设置总条数
int totalCount = this.getTotalCount();
pageBean.setTotalCount(totalCount);
pageBean.setTotalPage(pageBean.getTotalPage());
//设置当前页
if(pageBean.getCurrentPage()<=0){
pageBean.setCurrentPage(1);
}else if(pageBean.getCurrentPage()>pageBean.getTotalPage()){
pageBean.setCurrentPage(pageBean.getTotalPage());
}
//查询分页数据
int currentPage = pageBean.getCurrentPage();
int pageCount = pageBean.getPageCount();
int startIndex = (currentPage-1)*pageCount;
String sql = "select * from emp limit ?,?";
QueryRunner qr = JdbcUtil.getQueryRunner();
List<Employee> pageData = qr.query(sql, new BeanListHandler<Employee>(Employee.class),startIndex,pageCount);
pageBean.setPageData(pageData);
}
// 获取数据总条数
public int getTotalCount() throws Exception{
String sql = "select count(*) from emp";
QueryRunner qr = JdbcUtil.getQueryRunner();
Long count = qr.query(sql, new ScalarHandler<Long>());
return count.intValue();
}
/*public static void main(String[] args) throws Exception{
String sql = "insert into emp values(null,?,?)";
PreparedStatement pst = JdbcUtil.dataSource.getConnection().prepareStatement(sql);
for(int i=0;i<20;i++){
pst.setString(1, "name"+i);
pst.setInt(2, 2+i);
pst.executeUpdate();
}
}*/
}