概述
基本概念
连接池是创建和管理一个连接的缓冲池技术,这些连接准备好被任何需要它们的线程使用,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。
原理
应用程序直接获取连接的缺点
用户每次请求都需要向数据库获得连接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库资源,并且极易造成数据库服务器内存溢出
连接池工作原理
系统初始化时将数据库连接作为对象存入连接池中,线程需要与数据库获得链接时,将不再新建立连接,而是从连接池选择一个连接,使用完后也不关闭连接,而是放回连接池中,以供下一个请求访问使用。
1.避免了频繁创建新的连接导致系统消耗和碎片内存
2.减少了创建连接消耗的时间,提高了系统反应速度
3.避免了连接没有释放而导致数据库连接遗漏问题
4.新的资源分配手段,通过最大连接数避免单个应用程序占据全部资源
C3P0连接池
手动设置连接池
/**
* 手动设置连接池
*/
@Test
public void demo1() {
Connection conn = null;
PreparedStatement pstate = null;
ResultSet rs = null;
try {
/*创建连接池*/
ComboPooledDataSource dataSource = new ComboPooledDataSource();
/*设置连接池参数*/
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///jdbctest?serverTimezone=UTC&characterEncoding=utf-8");
dataSource.setUser("root");
dataSource.setPassword("curry");
dataSource.setMaxPoolSize(20);//连接池最大连接数
dataSource.setInitialPoolSize(3);//同时连接数
conn = dataSource.getConnection();
String sql = "select * from jdbctest";
pstate = conn.prepareStatement(sql);
rs = pstate.executeQuery();
while(rs.next()) {
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getInt("age"));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
try {
JDBCUtils.release(rs, conn, pstate);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
使用配置文件方式
在类路径下写入c3p0-config.xml配置文件,创建连接池对象时会自动查找到该配置文件
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///jdbctest?serverTimezone=UTC&characterEncoding=utf8</property>
<property name="user">root</property>
<property name="password">curry</property>
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
</c3p0-config>
使用配置文件之后创建ComboPooledDataSource对像时会直接从目录中寻找该配置文件省去参数设置的流程
反射编程应用
从数据库查询数据并封装到实体类,诸如mybatis的ORM框架中映射的实现原理
实体类
/***
* 商品实体类
* @author Vbird
*
*/
public class Goods {
private int id;
private String name;
private float price;
private String desp;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getDesp() {
return desp;
}
public void setDesp(String desp) {
this.desp = desp;
}
@Override
public String toString() {
return id+"\t"+name+"\t"+price+"\t"+desp;
}
}
dao类
/***
* 商品dao类
* @author Vbird
*
*/
public class GoodsDao {
Connection conn = null;
PreparedStatement preState = null;
ResultSet rs = null;
/**
* 通过id获取数据
* @param id
* @return
* @throws NoSuchMethodException
* @throws SecurityException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
* @throws InstantiationException
* @throws SQLException
*/
public Goods getById(int id) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, SQLException {
Goods good = new Goods();
try {
conn = JDBCUtils.getConnection();
String sql ="select * from goods where id=?";
preState = conn.prepareStatement(sql);
preState.setInt(1, id);
rs = preState.executeQuery();
good = GoodsDao.convert(rs, Goods.class).get(0);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
JDBCUtils.release(rs,conn,preState);
} catch (SQLException e) {
e.printStackTrace();
}
}
return good;
}
/**
* 数据转换
* @param rs
* @param c
* @return
* @throws NoSuchMethodException
* @throws SecurityException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
* @throws SQLException
* @throws InstantiationException
*/
private static <T> List<T> convert(ResultSet rs,Class<T> c) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SQLException, InstantiationException {
List<T> list = new ArrayList<T>();
while(rs.next()) {
//创建实例对象
T t = c.newInstance();
//获取实体类的属性
Field fields[] = c.getDeclaredFields();
//执行每一个属性的set方法,将结果集中的数据进行封装
for(Field f:fields) {
//通过方法名和参数类型获得方法
Method method = c.getDeclaredMethod("set"+f.getName().substring(0,1).toUpperCase()+f.getName().substring(1), f.getType());
//执行方法
method.invoke(t, rs.getObject(f.getName()));
}
list.add(t);
}
return list;
}
}